144961713Sgirish /* 244961713Sgirish * CDDL HEADER START 344961713Sgirish * 444961713Sgirish * The contents of this file are subject to the terms of the 544961713Sgirish * Common Development and Distribution License (the "License"). 644961713Sgirish * You may not use this file except in compliance with the License. 744961713Sgirish * 844961713Sgirish * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 944961713Sgirish * or http://www.opensolaris.org/os/licensing. 1044961713Sgirish * See the License for the specific language governing permissions 1144961713Sgirish * and limitations under the License. 1244961713Sgirish * 1344961713Sgirish * When distributing Covered Code, include this CDDL HEADER in each 1444961713Sgirish * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1544961713Sgirish * If applicable, add the following below this CDDL HEADER, with the 1644961713Sgirish * fields enclosed by brackets "[]" replaced with your own identifying 1744961713Sgirish * information: Portions Copyright [yyyy] [name of copyright owner] 1844961713Sgirish * 1944961713Sgirish * CDDL HEADER END 2044961713Sgirish */ 2144961713Sgirish /* 22b80c1b63SSree Vemuri * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. 2344961713Sgirish */ 2444961713Sgirish 2544961713Sgirish /* 26c7a079a8SJonathan Haslam * This file contains preset event names from the Performance Application 27c7a079a8SJonathan Haslam * Programming Interface v3.5 which included the following notice: 28c7a079a8SJonathan Haslam * 29c7a079a8SJonathan Haslam * Copyright (c) 2005,6 30c7a079a8SJonathan Haslam * Innovative Computing Labs 31c7a079a8SJonathan Haslam * Computer Science Department, 32c7a079a8SJonathan Haslam * University of Tennessee, 33c7a079a8SJonathan Haslam * Knoxville, TN. 34c7a079a8SJonathan Haslam * All Rights Reserved. 35c7a079a8SJonathan Haslam * 36c7a079a8SJonathan Haslam * 37c7a079a8SJonathan Haslam * Redistribution and use in source and binary forms, with or without 38c7a079a8SJonathan Haslam * modification, are permitted provided that the following conditions are met: 39c7a079a8SJonathan Haslam * 40c7a079a8SJonathan Haslam * * Redistributions of source code must retain the above copyright notice, 41c7a079a8SJonathan Haslam * this list of conditions and the following disclaimer. 42c7a079a8SJonathan Haslam * * Redistributions in binary form must reproduce the above copyright 43c7a079a8SJonathan Haslam * notice, this list of conditions and the following disclaimer in the 44c7a079a8SJonathan Haslam * documentation and/or other materials provided with the distribution. 45c7a079a8SJonathan Haslam * * Neither the name of the University of Tennessee nor the names of its 46c7a079a8SJonathan Haslam * contributors may be used to endorse or promote products derived from 47c7a079a8SJonathan Haslam * this software without specific prior written permission. 48c7a079a8SJonathan Haslam * 49c7a079a8SJonathan Haslam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 50c7a079a8SJonathan Haslam * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51c7a079a8SJonathan Haslam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52c7a079a8SJonathan Haslam * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 53c7a079a8SJonathan Haslam * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54c7a079a8SJonathan Haslam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55c7a079a8SJonathan Haslam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56c7a079a8SJonathan Haslam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57c7a079a8SJonathan Haslam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58c7a079a8SJonathan Haslam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59c7a079a8SJonathan Haslam * POSSIBILITY OF SUCH DAMAGE. 60c7a079a8SJonathan Haslam * 61c7a079a8SJonathan Haslam * 62c7a079a8SJonathan Haslam * This open source software license conforms to the BSD License template. 63c7a079a8SJonathan Haslam */ 64c7a079a8SJonathan Haslam 65c7a079a8SJonathan Haslam /* 6644961713Sgirish * Niagara2 Performance Counter Backend 6744961713Sgirish */ 6844961713Sgirish 6944961713Sgirish #include <sys/cpuvar.h> 7044961713Sgirish #include <sys/systm.h> 7144961713Sgirish #include <sys/archsystm.h> 7244961713Sgirish #include <sys/cmn_err.h> 7344961713Sgirish #include <sys/cpc_impl.h> 7444961713Sgirish #include <sys/cpc_pcbe.h> 7544961713Sgirish #include <sys/modctl.h> 7644961713Sgirish #include <sys/machsystm.h> 7744961713Sgirish #include <sys/sdt.h> 7844961713Sgirish #include <sys/niagara2regs.h> 7944961713Sgirish #include <sys/hsvc.h> 808d4e547dSae112802 #include <sys/hypervisor_api.h> 818d4e547dSae112802 #include <sys/disp.h> 8244961713Sgirish 8359ac0c16Sdavemq /*LINTLIBRARY*/ 8444961713Sgirish static int ni2_pcbe_init(void); 8544961713Sgirish static uint_t ni2_pcbe_ncounters(void); 8644961713Sgirish static const char *ni2_pcbe_impl_name(void); 8744961713Sgirish static const char *ni2_pcbe_cpuref(void); 8844961713Sgirish static char *ni2_pcbe_list_events(uint_t picnum); 8944961713Sgirish static char *ni2_pcbe_list_attrs(void); 9044961713Sgirish static uint64_t ni2_pcbe_event_coverage(char *event); 9144961713Sgirish static uint64_t ni2_pcbe_overflow_bitmap(void); 9244961713Sgirish static int ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, 9344961713Sgirish uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data, 9444961713Sgirish void *token); 9544961713Sgirish static void ni2_pcbe_program(void *token); 9644961713Sgirish static void ni2_pcbe_allstop(void); 9744961713Sgirish static void ni2_pcbe_sample(void *token); 9844961713Sgirish static void ni2_pcbe_free(void *config); 9944961713Sgirish 10044961713Sgirish extern void ultra_setpcr(uint64_t); 10144961713Sgirish extern uint64_t ultra_getpcr(void); 10244961713Sgirish extern void ultra_setpic(uint64_t); 10344961713Sgirish extern uint64_t ultra_getpic(void); 10444961713Sgirish extern uint64_t ultra_gettick(void); 10544961713Sgirish extern char cpu_module_name[]; 10644961713Sgirish 1071e81ac6eSSree Vemuri #define L2_dmiss_ld_event 0x320 1081e81ac6eSSree Vemuri int pcbe_l2dmiss_ovtrap_enable = 0; 1091e81ac6eSSree Vemuri 11044961713Sgirish pcbe_ops_t ni2_pcbe_ops = { 11144961713Sgirish PCBE_VER_1, 11244961713Sgirish CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE, 11344961713Sgirish ni2_pcbe_ncounters, 11444961713Sgirish ni2_pcbe_impl_name, 11544961713Sgirish ni2_pcbe_cpuref, 11644961713Sgirish ni2_pcbe_list_events, 11744961713Sgirish ni2_pcbe_list_attrs, 11844961713Sgirish ni2_pcbe_event_coverage, 11944961713Sgirish ni2_pcbe_overflow_bitmap, 12044961713Sgirish ni2_pcbe_configure, 12144961713Sgirish ni2_pcbe_program, 12244961713Sgirish ni2_pcbe_allstop, 12344961713Sgirish ni2_pcbe_sample, 12444961713Sgirish ni2_pcbe_free 12544961713Sgirish }; 12644961713Sgirish 12744961713Sgirish typedef struct _ni2_pcbe_config { 12844961713Sgirish uint_t pcbe_picno; /* 0 for pic0 or 1 for pic1 */ 12944961713Sgirish uint32_t pcbe_evsel; /* %pcr event code unshifted */ 13044961713Sgirish uint32_t pcbe_flags; /* hpriv/user/system/priv */ 13144961713Sgirish uint32_t pcbe_pic; /* unshifted raw %pic value */ 13244961713Sgirish } ni2_pcbe_config_t; 13344961713Sgirish 13444961713Sgirish typedef struct _ni2_event { 13544961713Sgirish const char *name; 13644961713Sgirish const uint32_t emask; 13744961713Sgirish const uint32_t emask_valid; /* Mask of unreserved MASK bits */ 13844961713Sgirish } ni2_event_t; 13944961713Sgirish 140c7a079a8SJonathan Haslam typedef struct _ni2_generic_event { 141c7a079a8SJonathan Haslam char *name; 142c7a079a8SJonathan Haslam char *event; 143c7a079a8SJonathan Haslam } ni2_generic_event_t; 144c7a079a8SJonathan Haslam 1454df55fdeSJanie Lu #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_PCR_PRIV_SHIFT) 14644961713Sgirish #define EV_END {NULL, 0, 0} 147c7a079a8SJonathan Haslam #define GEN_EV_END {NULL, NULL} 14844961713Sgirish 1498d4e547dSae112802 static const uint64_t allstopped = (ULTRA_PCR_PRIVPIC | 1504df55fdeSJanie Lu CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1); 15144961713Sgirish 1528d4e547dSae112802 /* 1538d4e547dSae112802 * We update this array in the program and allstop routine. The array 1548d4e547dSae112802 * is checked in the sample routine to allow us to only perform the 1558d4e547dSae112802 * PCR.ht bit check when counting is in progress. 1568d4e547dSae112802 */ 1578d4e547dSae112802 static boolean_t ni2_cpc_counting[NCPU]; 1588d4e547dSae112802 159bb4f5042Sha137994 static ni2_event_t ni2_events[] = { 1608d4e547dSae112802 { "Idle_strands", 0x000, 0x00 }, 1618d4e547dSae112802 { "Br_completed", 0x201, 0xff }, 1628d4e547dSae112802 { "Br_taken", 0x202, 0xff }, 1638d4e547dSae112802 { "Instr_FGU_arithmetic", 0x204, 0xff }, 1648d4e547dSae112802 { "Instr_ld", 0x208, 0xff }, 1658d4e547dSae112802 { "Instr_st", 0x210, 0xff }, 1668d4e547dSae112802 { "Instr_sw", 0x220, 0xff }, 1678d4e547dSae112802 { "Instr_other", 0x240, 0xff }, 1688d4e547dSae112802 { "Atomics", 0x280, 0xff }, 1698d4e547dSae112802 { "Instr_cnt", 0x2fd, 0xff }, 1708d4e547dSae112802 { "IC_miss", 0x301, 0x33 }, 1718d4e547dSae112802 { "DC_miss", 0x302, 0x33 }, 1728d4e547dSae112802 { "L2_imiss", 0x310, 0x33 }, 1738d4e547dSae112802 { "L2_dmiss_ld", 0x320, 0x33 }, 1748d4e547dSae112802 { "ITLB_HWTW_ref_L2", 0x404, 0x3c }, 1758d4e547dSae112802 { "DTLB_HWTW_ref_L2", 0x408, 0x3c }, 1768d4e547dSae112802 { "ITLB_HWTW_miss_L2", 0x410, 0x3c }, 1778d4e547dSae112802 { "DTLB_HWTW_miss_L2", 0x420, 0x3c }, 1788d4e547dSae112802 { "Stream_ld_to_PCX", 0x501, 0x3f }, 1798d4e547dSae112802 { "Stream_st_to_PCX", 0x502, 0x3f }, 1808d4e547dSae112802 { "CPU_ld_to_PCX", 0x504, 0x3f }, 1818d4e547dSae112802 { "CPU_ifetch_to_PCX", 0x508, 0x3f }, 1828d4e547dSae112802 { "CPU_st_to_PCX", 0x510, 0x3f }, 1838d4e547dSae112802 { "MMU_ld_to_PCX", 0x520, 0x3f }, 1844df55fdeSJanie Lu #ifdef KT_IMPL 1854df55fdeSJanie Lu { "DES_3DES_op", 0x601, 0xff }, 1864df55fdeSJanie Lu { "AES_op", 0x602, 0xff }, 1874df55fdeSJanie Lu { "Kasumi_op", 0x604, 0xff }, 1884df55fdeSJanie Lu { "MD5_SHA-1_SHA-256_op", 0x608, 0xff }, 1894df55fdeSJanie Lu { "MA_op", 0x610, 0xff }, 1904df55fdeSJanie Lu { "CRC_TCPIP_cksum", 0x620, 0xff }, 1914df55fdeSJanie Lu { "DES_3DES_busy_cycle", 0x701, 0xff }, 1924df55fdeSJanie Lu { "AES_busy_cycle", 0x702, 0xff }, 1934df55fdeSJanie Lu { "Kasumi_busy_cycle", 0x704, 0xff }, 1944df55fdeSJanie Lu { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0xff }, 1954df55fdeSJanie Lu { "MA_busy_cycle", 0x710, 0xff }, 1964df55fdeSJanie Lu { "CRC_MPA_cksum", 0x720, 0xff }, 1974df55fdeSJanie Lu #else 1988d4e547dSae112802 { "DES_3DES_op", 0x601, 0x3f }, 1998d4e547dSae112802 { "AES_op", 0x602, 0x3f }, 2008d4e547dSae112802 { "RC4_op", 0x604, 0x3f }, 2018d4e547dSae112802 { "MD5_SHA-1_SHA-256_op", 0x608, 0x3f }, 2028d4e547dSae112802 { "MA_op", 0x610, 0x3f }, 2038d4e547dSae112802 { "CRC_TCPIP_cksum", 0x620, 0x3f }, 2048d4e547dSae112802 { "DES_3DES_busy_cycle", 0x701, 0x3f }, 2058d4e547dSae112802 { "AES_busy_cycle", 0x702, 0x3f }, 2068d4e547dSae112802 { "RC4_busy_cycle", 0x704, 0x3f }, 2078d4e547dSae112802 { "MD5_SHA-1_SHA-256_busy_cycle", 0x708, 0x3f }, 2088d4e547dSae112802 { "MA_busy_cycle", 0x710, 0x3f }, 2098d4e547dSae112802 { "CRC_MPA_cksum", 0x720, 0x3f }, 2104df55fdeSJanie Lu #endif 2118d4e547dSae112802 { "ITLB_miss", 0xb04, 0x0c }, 2128d4e547dSae112802 { "DTLB_miss", 0xb08, 0x0c }, 2138d4e547dSae112802 { "TLB_miss", 0xb0c, 0x0c }, 2148d4e547dSae112802 EV_END 2158d4e547dSae112802 }; 2168d4e547dSae112802 217c7a079a8SJonathan Haslam static ni2_generic_event_t ni2_generic_events[] = { 218c7a079a8SJonathan Haslam { "PAPI_tot_ins", "Instr_cnt" }, 219c7a079a8SJonathan Haslam { "PAPI_l1_dcm", "DC_miss" }, 220c7a079a8SJonathan Haslam { "PAPI_l1_icm", "IC_miss" }, 221c7a079a8SJonathan Haslam { "PAPI_l2_icm", "L2_imiss" }, 222c7a079a8SJonathan Haslam { "PAPI_l2_ldm", "L2_dmiss_ld" }, 223c7a079a8SJonathan Haslam { "PAPI_tlb_dm", "DTLB_miss" }, 224c7a079a8SJonathan Haslam { "PAPI_tlb_im", "ITLB_miss" }, 225c7a079a8SJonathan Haslam { "PAPI_tlb_tm", "TLB_miss" }, 226c7a079a8SJonathan Haslam { "PAPI_br_tkn", "Br_taken" }, 227c7a079a8SJonathan Haslam { "PAPI_br_ins", "Br_completed" }, 228c7a079a8SJonathan Haslam { "PAPI_ld_ins", "Instr_ld" }, 229c7a079a8SJonathan Haslam { "PAPI_sr_ins", "Instr_st" }, 23067b48423SJonathan Haslam { "PAPI_fp_ops", "Instr_FGU_arithmetic" }, 23167b48423SJonathan Haslam { "PAPI_fp_ins", "Instr_FGU_arithmetic" }, 232c7a079a8SJonathan Haslam GEN_EV_END 233c7a079a8SJonathan Haslam }; 234c7a079a8SJonathan Haslam 23544961713Sgirish static char *evlist; 23644961713Sgirish static size_t evlist_sz; 23744961713Sgirish static uint16_t pcr_pic0_mask; 23844961713Sgirish static uint16_t pcr_pic1_mask; 23944961713Sgirish 24044961713Sgirish #define CPU_REF_URL " Documentation for Sun processors can be found at: " \ 24144961713Sgirish "http://www.sun.com/processors/manuals" 24244961713Sgirish 24359ac0c16Sdavemq #if defined(NIAGARA2_IMPL) 24459ac0c16Sdavemq static const char *cpu_impl_name = "UltraSPARC T2"; 24559ac0c16Sdavemq static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2 User's Manual\" " 24644961713Sgirish "for descriptions of these events." CPU_REF_URL; 24759ac0c16Sdavemq #elif defined(VFALLS_IMPL) 24859ac0c16Sdavemq static const char *cpu_impl_name = "UltraSPARC T2+"; 24959ac0c16Sdavemq static const char *cpu_pcbe_ref = "See the \"UltraSPARC T2+ User's Manual\" " 25059ac0c16Sdavemq "for descriptions of these events." CPU_REF_URL; 2514df55fdeSJanie Lu #elif defined(KT_IMPL) 252*c4c6ba57SVivek Gavaskar static const char *cpu_impl_name = "SPARC T3"; 253*c4c6ba57SVivek Gavaskar static const char *cpu_pcbe_ref = "See the \"SPARC T3 User's Manual\" " 2544df55fdeSJanie Lu "for descriptions of these events." CPU_REF_URL; 25559ac0c16Sdavemq #endif 25644961713Sgirish 25759ac0c16Sdavemq static boolean_t cpu_hsvc_available = B_TRUE; 25844961713Sgirish 25944961713Sgirish static int 26044961713Sgirish ni2_pcbe_init(void) 26144961713Sgirish { 26244961713Sgirish ni2_event_t *evp; 263c7a079a8SJonathan Haslam ni2_generic_event_t *gevp; 26444961713Sgirish int status; 26559ac0c16Sdavemq uint64_t cpu_hsvc_major; 26659ac0c16Sdavemq uint64_t cpu_hsvc_minor; 26759ac0c16Sdavemq #if defined(NIAGARA2_IMPL) 26859ac0c16Sdavemq uint64_t hsvc_cpu_group = HSVC_GROUP_NIAGARA2_CPU; 26959ac0c16Sdavemq uint64_t hsvc_cpu_major = NIAGARA2_HSVC_MAJOR; 27059ac0c16Sdavemq #elif defined(VFALLS_IMPL) 27159ac0c16Sdavemq uint64_t hsvc_cpu_group = HSVC_GROUP_VFALLS_CPU; 27259ac0c16Sdavemq uint64_t hsvc_cpu_major = VFALLS_HSVC_MAJOR; 2734df55fdeSJanie Lu #elif defined(KT_IMPL) 2744df55fdeSJanie Lu uint64_t hsvc_cpu_group = HSVC_GROUP_KT_CPU; 2754df55fdeSJanie Lu uint64_t hsvc_cpu_major = KT_HSVC_MAJOR; 27659ac0c16Sdavemq #endif 27744961713Sgirish 2784df55fdeSJanie Lu pcr_pic0_mask = CPC_PCR_PIC0_MASK; 2794df55fdeSJanie Lu pcr_pic1_mask = CPC_PCR_PIC1_MASK; 28044961713Sgirish 28144961713Sgirish /* 28244961713Sgirish * Validate API version for Niagara2 specific hypervisor services 28344961713Sgirish */ 28459ac0c16Sdavemq status = hsvc_version(hsvc_cpu_group, &cpu_hsvc_major, 28559ac0c16Sdavemq &cpu_hsvc_minor); 28659ac0c16Sdavemq if ((status != 0) || (cpu_hsvc_major != hsvc_cpu_major)) { 28744961713Sgirish cmn_err(CE_WARN, "hypervisor services not negotiated " 28859ac0c16Sdavemq "or unsupported major number: group: 0x%lx major: 0x%lx " 28959ac0c16Sdavemq "minor: 0x%lx errno: %d", hsvc_cpu_group, 29059ac0c16Sdavemq cpu_hsvc_major, cpu_hsvc_minor, status); 29159ac0c16Sdavemq cpu_hsvc_available = B_FALSE; 29244961713Sgirish } 293bb4f5042Sha137994 29444961713Sgirish /* 29544961713Sgirish * Construct event list. 29644961713Sgirish * 29744961713Sgirish * First pass: Calculate size needed. We'll need an additional byte 29844961713Sgirish * for the NULL pointer during the last strcat. 29944961713Sgirish * 30044961713Sgirish * Second pass: Copy strings. 30144961713Sgirish */ 30244961713Sgirish for (evp = ni2_events; evp->name != NULL; evp++) 30344961713Sgirish evlist_sz += strlen(evp->name) + 1; 30444961713Sgirish 305c7a079a8SJonathan Haslam for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) 306c7a079a8SJonathan Haslam evlist_sz += strlen(gevp->name) + 1; 307c7a079a8SJonathan Haslam 30844961713Sgirish evlist = kmem_alloc(evlist_sz + 1, KM_SLEEP); 30944961713Sgirish evlist[0] = '\0'; 31044961713Sgirish 31144961713Sgirish for (evp = ni2_events; evp->name != NULL; evp++) { 31244961713Sgirish (void) strcat(evlist, evp->name); 31344961713Sgirish (void) strcat(evlist, ","); 31444961713Sgirish } 315c7a079a8SJonathan Haslam 316c7a079a8SJonathan Haslam for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) { 317c7a079a8SJonathan Haslam (void) strcat(evlist, gevp->name); 318c7a079a8SJonathan Haslam (void) strcat(evlist, ","); 319c7a079a8SJonathan Haslam } 320c7a079a8SJonathan Haslam 32144961713Sgirish /* 32244961713Sgirish * Remove trailing comma. 32344961713Sgirish */ 32444961713Sgirish evlist[evlist_sz - 1] = '\0'; 32544961713Sgirish 32644961713Sgirish return (0); 32744961713Sgirish } 32844961713Sgirish 32944961713Sgirish static uint_t 33044961713Sgirish ni2_pcbe_ncounters(void) 33144961713Sgirish { 33244961713Sgirish return (2); 33344961713Sgirish } 33444961713Sgirish 33544961713Sgirish static const char * 33644961713Sgirish ni2_pcbe_impl_name(void) 33744961713Sgirish { 33859ac0c16Sdavemq return (cpu_impl_name); 33944961713Sgirish } 34044961713Sgirish 34144961713Sgirish static const char * 34244961713Sgirish ni2_pcbe_cpuref(void) 34344961713Sgirish { 34459ac0c16Sdavemq return (cpu_pcbe_ref); 34544961713Sgirish } 34644961713Sgirish 34744961713Sgirish static char * 34844961713Sgirish ni2_pcbe_list_events(uint_t picnum) 34944961713Sgirish { 35044961713Sgirish ASSERT(picnum < cpc_ncounters); 35144961713Sgirish 35244961713Sgirish return (evlist); 35344961713Sgirish } 35444961713Sgirish 35544961713Sgirish static char * 35644961713Sgirish ni2_pcbe_list_attrs(void) 35744961713Sgirish { 35859ac0c16Sdavemq if (cpu_hsvc_available == B_TRUE) 35959ac0c16Sdavemq #if defined(NIAGARA2_IMPL) 36044961713Sgirish return ("hpriv,emask"); 36159ac0c16Sdavemq #elif defined(VFALLS_IMPL) 36259ac0c16Sdavemq return ("hpriv,l2ctl,emask"); 3634df55fdeSJanie Lu #elif defined(KT_IMPL) 3644df55fdeSJanie Lu return ("hpriv,l2ctl,emask,sample"); 36559ac0c16Sdavemq #endif 36644961713Sgirish else 3674df55fdeSJanie Lu #if defined(KT_IMPL) 3684df55fdeSJanie Lu return ("emask,sample"); 3694df55fdeSJanie Lu #else 37044961713Sgirish return ("emask"); 3714df55fdeSJanie Lu #endif 37244961713Sgirish } 37344961713Sgirish 374c7a079a8SJonathan Haslam static ni2_generic_event_t * 375c7a079a8SJonathan Haslam find_generic_event(char *name) 376c7a079a8SJonathan Haslam { 377c7a079a8SJonathan Haslam ni2_generic_event_t *gevp; 378c7a079a8SJonathan Haslam 379c7a079a8SJonathan Haslam for (gevp = ni2_generic_events; gevp->name != NULL; gevp++) { 380c7a079a8SJonathan Haslam if (strcmp(name, gevp->name) == 0) 381c7a079a8SJonathan Haslam return (gevp); 382c7a079a8SJonathan Haslam } 383c7a079a8SJonathan Haslam 384c7a079a8SJonathan Haslam return (NULL); 385c7a079a8SJonathan Haslam } 386c7a079a8SJonathan Haslam 38744961713Sgirish static ni2_event_t * 38844961713Sgirish find_event(char *name) 38944961713Sgirish { 39044961713Sgirish ni2_event_t *evp; 39144961713Sgirish 39244961713Sgirish for (evp = ni2_events; evp->name != NULL; evp++) 39344961713Sgirish if (strcmp(name, evp->name) == 0) 39444961713Sgirish return (evp); 39544961713Sgirish 39644961713Sgirish return (NULL); 39744961713Sgirish } 39844961713Sgirish 39944961713Sgirish /*ARGSUSED*/ 40044961713Sgirish static uint64_t 40144961713Sgirish ni2_pcbe_event_coverage(char *event) 40244961713Sgirish { 40344961713Sgirish /* 404b885580bSAlexander Kolbasov * Check whether counter event is supported 405b885580bSAlexander Kolbasov */ 406b885580bSAlexander Kolbasov if (find_event(event) == NULL && find_generic_event(event) == NULL) 407b885580bSAlexander Kolbasov return (0); 408b885580bSAlexander Kolbasov 409b885580bSAlexander Kolbasov /* 41044961713Sgirish * Fortunately, both pic0 and pic1 can count all events. 41144961713Sgirish */ 41244961713Sgirish return (0x3); 41344961713Sgirish } 41444961713Sgirish 41544961713Sgirish static uint64_t 41644961713Sgirish ni2_pcbe_overflow_bitmap(void) 41744961713Sgirish { 41844961713Sgirish uint64_t pcr, overflow; 41944961713Sgirish uint64_t pic; 42044961713Sgirish uint32_t pic0, pic1; 42144961713Sgirish boolean_t update_pic = B_FALSE; 4224df55fdeSJanie Lu boolean_t pic_inrange = B_FALSE; 42344961713Sgirish 42444961713Sgirish ASSERT(getpil() >= DISP_LEVEL); 42544961713Sgirish pcr = ultra_getpcr(); 42644961713Sgirish DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 4274df55fdeSJanie Lu overflow = (pcr & CPC_PCR_OV0_MASK) >> 4284df55fdeSJanie Lu CPC_PCR_OV0_SHIFT; 4294df55fdeSJanie Lu overflow |= (pcr & CPC_PCR_OV1_MASK) >> 4304df55fdeSJanie Lu CPC_PCR_OV1_SHIFT; 4318d4e547dSae112802 4328d4e547dSae112802 pic = ultra_getpic(); 4338d4e547dSae112802 pic0 = (uint32_t)(pic & PIC0_MASK); 4348d4e547dSae112802 pic1 = (uint32_t)((pic >> PIC1_SHIFT) & PIC0_MASK); 4358d4e547dSae112802 4364df55fdeSJanie Lu pcr |= (CPC_PCR_HOLDOV0 | CPC_PCR_HOLDOV1); 4378d4e547dSae112802 4388d4e547dSae112802 if (overflow & 0x1) { 4394df55fdeSJanie Lu pcr &= ~(CPC_PCR_OV0_MASK | 4404df55fdeSJanie Lu CPC_PCR_HOLDOV0); 4414df55fdeSJanie Lu pic_inrange = PIC_IN_OV_RANGE(pic0); 4424df55fdeSJanie Lu #if defined(KT_IMPL) 4434df55fdeSJanie Lu if (pcr & CPC_PCR_SAMPLE_MODE_MASK) 4444df55fdeSJanie Lu pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic0); 4454df55fdeSJanie Lu #endif 4464df55fdeSJanie Lu if (pic_inrange) { 44744961713Sgirish pic0 = 0; 44844961713Sgirish update_pic = B_TRUE; 44944961713Sgirish } 4508d4e547dSae112802 } 4518d4e547dSae112802 4528d4e547dSae112802 if (overflow & 0x2) { 4534df55fdeSJanie Lu pcr &= ~(CPC_PCR_OV1_MASK | 4544df55fdeSJanie Lu CPC_PCR_HOLDOV1); 4554df55fdeSJanie Lu pic_inrange = PIC_IN_OV_RANGE(pic1); 4564df55fdeSJanie Lu #if defined(KT_IMPL) 4574df55fdeSJanie Lu if (pcr & CPC_PCR_SAMPLE_MODE_MASK) 4584df55fdeSJanie Lu pic_inrange = SAMPLE_PIC_IN_OV_RANGE(pic1); 4594df55fdeSJanie Lu #endif 4604df55fdeSJanie Lu if (pic_inrange) { 46144961713Sgirish pic1 = 0; 46244961713Sgirish update_pic = B_TRUE; 46344961713Sgirish } 4648d4e547dSae112802 } 46544961713Sgirish 46644961713Sgirish if (update_pic) 46744961713Sgirish ultra_setpic(((uint64_t)pic1 << PIC1_SHIFT) | pic0); 46844961713Sgirish 4698d4e547dSae112802 /* 4708d4e547dSae112802 * The HV interface does not need to be used here because we are 4718d4e547dSae112802 * only resetting the OV bits and do not need to set the HT bit. 4728d4e547dSae112802 */ 4738d4e547dSae112802 DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 4748d4e547dSae112802 ultra_setpcr(pcr); 4758d4e547dSae112802 47644961713Sgirish return (overflow); 47744961713Sgirish } 47844961713Sgirish 47944961713Sgirish /*ARGSUSED*/ 48044961713Sgirish static int 48144961713Sgirish ni2_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags, 48244961713Sgirish uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token) 48344961713Sgirish { 48444961713Sgirish ni2_pcbe_config_t *cfg; 48544961713Sgirish ni2_pcbe_config_t *other_config; 48644961713Sgirish ni2_event_t *evp; 487c7a079a8SJonathan Haslam ni2_generic_event_t *gevp; 48844961713Sgirish int i; 48944961713Sgirish uint32_t evsel; 4904df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL) 491a588362cSSree Vemuri uint64_t l2ctl = 0; 492a588362cSSree Vemuri #endif 49344961713Sgirish 49444961713Sgirish /* 49544961713Sgirish * If we've been handed an existing configuration, we need only preset 49644961713Sgirish * the counter value. 49744961713Sgirish */ 49844961713Sgirish if (*data != NULL) { 49944961713Sgirish cfg = *data; 50044961713Sgirish cfg->pcbe_pic = (uint32_t)preset; 50144961713Sgirish return (0); 50244961713Sgirish } 50344961713Sgirish 50444961713Sgirish if (picnum > 1) 50544961713Sgirish return (CPC_INVALID_PICNUM); 50644961713Sgirish 507c7a079a8SJonathan Haslam 508c7a079a8SJonathan Haslam if ((evp = find_event(event)) == NULL) { 509c7a079a8SJonathan Haslam if ((gevp = find_generic_event(event)) != NULL) { 510c7a079a8SJonathan Haslam evp = find_event(gevp->event); 511c7a079a8SJonathan Haslam ASSERT(evp != NULL); 512c7a079a8SJonathan Haslam 513c7a079a8SJonathan Haslam if (nattrs > 0) 514c7a079a8SJonathan Haslam return (CPC_ATTRIBUTE_OUT_OF_RANGE); 515c7a079a8SJonathan Haslam } else { 51644961713Sgirish return (CPC_INVALID_EVENT); 517c7a079a8SJonathan Haslam } 518c7a079a8SJonathan Haslam } 51944961713Sgirish 52044961713Sgirish evsel = evp->emask; 52144961713Sgirish 52244961713Sgirish for (i = 0; i < nattrs; i++) { 52344961713Sgirish if (strcmp(attrs[i].ka_name, "hpriv") == 0) { 52444961713Sgirish if (attrs[i].ka_val != 0) 5258d4e547dSae112802 flags |= CPC_COUNT_HV; 52644961713Sgirish } else if (strcmp(attrs[i].ka_name, "emask") == 0) { 52744961713Sgirish if ((attrs[i].ka_val | evp->emask_valid) != 52844961713Sgirish evp->emask_valid) 52944961713Sgirish return (CPC_ATTRIBUTE_OUT_OF_RANGE); 53044961713Sgirish evsel |= attrs[i].ka_val; 5314df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL) 53259ac0c16Sdavemq } else if (strcmp(attrs[i].ka_name, "l2ctl") == 0) { 5334df55fdeSJanie Lu if ((attrs[i].ka_val | L2_CTL_MASK) != 5344df55fdeSJanie Lu L2_CTL_MASK) 53559ac0c16Sdavemq return (CPC_ATTRIBUTE_OUT_OF_RANGE); 536a588362cSSree Vemuri else 537a588362cSSree Vemuri l2ctl = attrs[i].ka_val; 53859ac0c16Sdavemq #endif 5394df55fdeSJanie Lu #if defined(KT_IMPL) 5404df55fdeSJanie Lu } else if (strcmp(attrs[i].ka_name, "sample") == 0) { 5414df55fdeSJanie Lu if (attrs[i].ka_val != 0) 5424df55fdeSJanie Lu flags |= CPC_COUNT_SAMPLE_MODE; 5434df55fdeSJanie Lu #endif 54444961713Sgirish } else 54544961713Sgirish return (CPC_INVALID_ATTRIBUTE); 54644961713Sgirish } 54744961713Sgirish 5484df55fdeSJanie Lu #if defined(VFALLS_IMPL) || defined(KT_IMPL) 549a588362cSSree Vemuri /* 550a588362cSSree Vemuri * Set PERF_CONTROL bits in L2_CONTROL_REG only when events have 551a588362cSSree Vemuri * SL bits equal to 3. 552a588362cSSree Vemuri */ 553b80c1b63SSree Vemuri if ((evsel & SL_MASK) == SL3_MASK) { 5544df55fdeSJanie Lu if ((hv_niagara_setperf(HV_L2_CTL, l2ctl)) != 0) 555a588362cSSree Vemuri return (CPC_HV_NO_ACCESS); 556a588362cSSree Vemuri } 557a588362cSSree Vemuri #endif 558a588362cSSree Vemuri 55944961713Sgirish /* 56044961713Sgirish * Find other requests that will be programmed with this one, and ensure 56144961713Sgirish * the flags don't conflict. 56244961713Sgirish */ 56344961713Sgirish if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) && 56444961713Sgirish (other_config->pcbe_flags != flags)) 56544961713Sgirish return (CPC_CONFLICTING_REQS); 56644961713Sgirish 5678d4e547dSae112802 /* 5688d4e547dSae112802 * If the hpriv attribute is present, make sure we have 5698d4e547dSae112802 * access to hyperprivileged events before continuing with 5708d4e547dSae112802 * this configuration. If we can set the ht bit in the PCR 5718d4e547dSae112802 * successfully, we must have access to hyperprivileged 5728d4e547dSae112802 * events. 5738d4e547dSae112802 * 5748d4e547dSae112802 * If this is a static per-CPU configuration, the CPC 5758d4e547dSae112802 * driver ensures there can not be more than one for this 5768d4e547dSae112802 * CPU. If this is a per-LWP configuration, the driver 5778d4e547dSae112802 * ensures no static per-CPU counting is ongoing and that 5788d4e547dSae112802 * the target LWP is not already being monitored. 5798d4e547dSae112802 */ 5808d4e547dSae112802 if (flags & CPC_COUNT_HV) { 5818d4e547dSae112802 kpreempt_disable(); 5828d4e547dSae112802 5838d4e547dSae112802 DTRACE_PROBE1(niagara2__setpcr, uint64_t, 5844df55fdeSJanie Lu allstopped | CPC_PCR_HT); 5854df55fdeSJanie Lu if (hv_niagara_setperf(HV_SPARC_CTL, 5864df55fdeSJanie Lu allstopped | CPC_PCR_HT) != H_EOK) { 5878d4e547dSae112802 kpreempt_enable(); 5888d4e547dSae112802 return (CPC_HV_NO_ACCESS); 5898d4e547dSae112802 } 5908d4e547dSae112802 5918d4e547dSae112802 DTRACE_PROBE1(niagara2__setpcr, uint64_t, allstopped); 5924df55fdeSJanie Lu (void) hv_niagara_setperf(HV_SPARC_CTL, allstopped); 5938d4e547dSae112802 5948d4e547dSae112802 kpreempt_enable(); 5958d4e547dSae112802 } 5968d4e547dSae112802 59744961713Sgirish cfg = kmem_alloc(sizeof (*cfg), KM_SLEEP); 59844961713Sgirish 59944961713Sgirish cfg->pcbe_picno = picnum; 60044961713Sgirish cfg->pcbe_evsel = evsel; 60144961713Sgirish cfg->pcbe_flags = flags; 60244961713Sgirish cfg->pcbe_pic = (uint32_t)preset; 60344961713Sgirish 60444961713Sgirish *data = cfg; 60544961713Sgirish return (0); 60644961713Sgirish } 60744961713Sgirish 60844961713Sgirish static void 60944961713Sgirish ni2_pcbe_program(void *token) 61044961713Sgirish { 61144961713Sgirish ni2_pcbe_config_t *pic0; 61244961713Sgirish ni2_pcbe_config_t *pic1; 61344961713Sgirish ni2_pcbe_config_t *tmp; 61444961713Sgirish ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 61544961713Sgirish uint64_t pcr; 61644961713Sgirish uint64_t curpic; 61744961713Sgirish uint64_t toe; 61844961713Sgirish 61944961713Sgirish /* enable trap-on-event for pic0 and pic1 */ 6204df55fdeSJanie Lu toe = (CPC_PCR_TOE0 | CPC_PCR_TOE1); 62144961713Sgirish 62244961713Sgirish if ((pic0 = (ni2_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) == 62344961713Sgirish NULL) 62444961713Sgirish panic("ni2_pcbe: token %p has no configs", token); 62544961713Sgirish 62644961713Sgirish if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) { 62744961713Sgirish pic1 = &nullcfg; 62844961713Sgirish nullcfg.pcbe_flags = pic0->pcbe_flags; 6294df55fdeSJanie Lu toe = CPC_PCR_TOE0; /* enable trap-on-event for pic0 */ 63044961713Sgirish } 63144961713Sgirish 63244961713Sgirish if (pic0->pcbe_picno != 0) { 63344961713Sgirish /* 63444961713Sgirish * pic0 is counter 1, so if we need the null config it should 63544961713Sgirish * be counter 0. 63644961713Sgirish */ 63744961713Sgirish nullcfg.pcbe_picno = 0; 63844961713Sgirish tmp = pic0; 63944961713Sgirish pic0 = pic1; 64044961713Sgirish pic1 = tmp; 6414df55fdeSJanie Lu toe = CPC_PCR_TOE1; /* enable trap-on-event for pic1 */ 64244961713Sgirish } 64344961713Sgirish 64444961713Sgirish if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 64559ac0c16Sdavemq panic("%s: bad config on token %p\n", cpu_impl_name, token); 64644961713Sgirish 64744961713Sgirish /* 64844961713Sgirish * UltraSPARC does not allow pic0 to be configured differently 64944961713Sgirish * from pic1. If the flags on these two configurations are 65044961713Sgirish * different, they are incompatible. This condition should be 65144961713Sgirish * caught at configure time. 65244961713Sgirish */ 65344961713Sgirish ASSERT(pic0->pcbe_flags == pic1->pcbe_flags); 65444961713Sgirish 6558d4e547dSae112802 ni2_pcbe_allstop(); 6568d4e547dSae112802 65744961713Sgirish ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) | 65844961713Sgirish (uint64_t)pic0->pcbe_pic); 65944961713Sgirish 6604df55fdeSJanie Lu pcr = (pic0->pcbe_evsel & pcr_pic0_mask) << CPC_PCR_PIC0_SHIFT; 66144961713Sgirish pcr |= (pic1->pcbe_evsel & pcr_pic1_mask) << 6624df55fdeSJanie Lu CPC_PCR_PIC1_SHIFT; 66344961713Sgirish 66444961713Sgirish if (pic0->pcbe_flags & CPC_COUNT_USER) 6654df55fdeSJanie Lu pcr |= (1ull << CPC_PCR_UT_SHIFT); 66644961713Sgirish if (pic0->pcbe_flags & CPC_COUNT_SYSTEM) 6674df55fdeSJanie Lu pcr |= (1ull << CPC_PCR_ST_SHIFT); 6688d4e547dSae112802 if (pic0->pcbe_flags & CPC_COUNT_HV) 6694df55fdeSJanie Lu pcr |= (1ull << CPC_PCR_HT_SHIFT); 6704df55fdeSJanie Lu #if defined(KT_IMPL) 6714df55fdeSJanie Lu if (pic0->pcbe_flags & CPC_COUNT_SAMPLE_MODE) 6724df55fdeSJanie Lu pcr |= (1ull << CPC_PCR_SAMPLE_MODE_SHIFT); 6734df55fdeSJanie Lu #endif 6741e81ac6eSSree Vemuri 6751e81ac6eSSree Vemuri if (pcbe_l2dmiss_ovtrap_enable == 0) { 6761e81ac6eSSree Vemuri /* 6771e81ac6eSSree Vemuri * SW workaround for HW Erratum 108. 6781e81ac6eSSree Vemuri * Disable overflow interrupts when L2_dmiss_ld event is 6791e81ac6eSSree Vemuri * selected. 6801e81ac6eSSree Vemuri */ 6811e81ac6eSSree Vemuri if ((pic0->pcbe_evsel & L2_dmiss_ld_event) == L2_dmiss_ld_event) 6821e81ac6eSSree Vemuri toe &= ~CPC_PCR_TOE0; 6831e81ac6eSSree Vemuri 6841e81ac6eSSree Vemuri if ((pic1->pcbe_evsel & L2_dmiss_ld_event) == L2_dmiss_ld_event) 6851e81ac6eSSree Vemuri toe &= ~CPC_PCR_TOE1; 6861e81ac6eSSree Vemuri } 68744961713Sgirish pcr |= toe; 68844961713Sgirish 68944961713Sgirish DTRACE_PROBE1(niagara2__setpcr, uint64_t, pcr); 69044961713Sgirish 6918d4e547dSae112802 if (pic0->pcbe_flags & CPC_COUNT_HV) { 69244961713Sgirish /* 6938d4e547dSae112802 * The ht bit in the PCR is only writable in 6948d4e547dSae112802 * hyperprivileged mode. So if we are counting 6958d4e547dSae112802 * hpriv events, we must use the HV interface 6968d4e547dSae112802 * hv_niagara_setperf to set the PCR. If this 6978d4e547dSae112802 * fails, assume we no longer have access to 6988d4e547dSae112802 * hpriv events. 69944961713Sgirish */ 7004df55fdeSJanie Lu if (hv_niagara_setperf(HV_SPARC_CTL, pcr) != H_EOK) { 7018d4e547dSae112802 kcpc_invalidate_config(token); 7028d4e547dSae112802 return; 7038d4e547dSae112802 } 70444961713Sgirish } else 7058d4e547dSae112802 /* Set the PCR with no hpriv event counting enabled. */ 70644961713Sgirish ultra_setpcr(pcr); 70744961713Sgirish 7088d4e547dSae112802 ni2_cpc_counting[CPU->cpu_id] = B_TRUE; 7098d4e547dSae112802 71044961713Sgirish /* 71144961713Sgirish * On UltraSPARC, only read-to-read counts are accurate. We cannot 71244961713Sgirish * expect the value we wrote into the PIC, above, to be there after 71344961713Sgirish * starting the counter. We must sample the counter value now and use 71444961713Sgirish * that as the baseline for future samples. 71544961713Sgirish */ 71644961713Sgirish curpic = ultra_getpic(); 71744961713Sgirish pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 71844961713Sgirish pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 71944961713Sgirish 72044961713Sgirish DTRACE_PROBE1(niagara2__newpic, uint64_t, curpic); 72144961713Sgirish } 72244961713Sgirish 72344961713Sgirish static void 72444961713Sgirish ni2_pcbe_allstop(void) 72544961713Sgirish { 7268d4e547dSae112802 /* 7278d4e547dSae112802 * We use the HV interface here because if we were counting 7288d4e547dSae112802 * hyperprivileged events, we must reset the PCR.ht bit to stop 7298d4e547dSae112802 * the counting. In the event that this HV call fails, we fall 7308d4e547dSae112802 * back on ultra_setpcr which does not have write access to the 7318d4e547dSae112802 * ht bit. 7328d4e547dSae112802 */ 7334df55fdeSJanie Lu if (hv_niagara_setperf(HV_SPARC_CTL, allstopped) != H_EOK) 73444961713Sgirish ultra_setpcr(allstopped); 7358d4e547dSae112802 7368d4e547dSae112802 ni2_cpc_counting[CPU->cpu_id] = B_FALSE; 73744961713Sgirish } 73844961713Sgirish 73944961713Sgirish static void 74044961713Sgirish ni2_pcbe_sample(void *token) 74144961713Sgirish { 74244961713Sgirish uint64_t curpic; 74344961713Sgirish int64_t diff; 74444961713Sgirish uint64_t *pic0_data; 74544961713Sgirish uint64_t *pic1_data; 74644961713Sgirish uint64_t *dtmp; 74744961713Sgirish uint64_t tmp; 7488d4e547dSae112802 uint64_t pcr; 74944961713Sgirish ni2_pcbe_config_t *pic0; 75044961713Sgirish ni2_pcbe_config_t *pic1; 75144961713Sgirish ni2_pcbe_config_t nullcfg = { 1, 0, 0, 0 }; 75244961713Sgirish ni2_pcbe_config_t *ctmp; 75344961713Sgirish 75444961713Sgirish curpic = ultra_getpic(); 75544961713Sgirish DTRACE_PROBE1(niagara2__getpic, uint64_t, curpic); 75644961713Sgirish 75744961713Sgirish if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL) 75859ac0c16Sdavemq panic("%s: token %p has no configs", cpu_impl_name, token); 75944961713Sgirish 76044961713Sgirish if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) { 76144961713Sgirish pic1 = &nullcfg; 76244961713Sgirish pic1_data = &tmp; 76344961713Sgirish } 76444961713Sgirish 76544961713Sgirish if (pic0->pcbe_picno != 0) { 76644961713Sgirish nullcfg.pcbe_picno = 0; 76744961713Sgirish ctmp = pic0; 76844961713Sgirish pic0 = pic1; 76944961713Sgirish pic1 = ctmp; 77044961713Sgirish dtmp = pic0_data; 77144961713Sgirish pic0_data = pic1_data; 77244961713Sgirish pic1_data = dtmp; 77344961713Sgirish } 77444961713Sgirish 77544961713Sgirish if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1) 77659ac0c16Sdavemq panic("%s: bad config on token %p\n", cpu_impl_name, token); 77744961713Sgirish 7788d4e547dSae112802 7798d4e547dSae112802 if (pic0->pcbe_flags & CPC_COUNT_HV) { 7808d4e547dSae112802 /* 7818d4e547dSae112802 * If the hpriv attribute is present, but the HT bit 7828d4e547dSae112802 * is not set in the PCR, access to hyperprivileged 7838d4e547dSae112802 * events must have been revoked. Only perform this 7848d4e547dSae112802 * check if counting is not stopped. 7858d4e547dSae112802 */ 7868d4e547dSae112802 pcr = ultra_getpcr(); 7878d4e547dSae112802 DTRACE_PROBE1(niagara2__getpcr, uint64_t, pcr); 7888d4e547dSae112802 if (ni2_cpc_counting[CPU->cpu_id] && 7894df55fdeSJanie Lu !(pcr & CPC_PCR_HT)) { 7908d4e547dSae112802 kcpc_invalidate_config(token); 7918d4e547dSae112802 return; 7928d4e547dSae112802 } 7938d4e547dSae112802 } 7948d4e547dSae112802 79544961713Sgirish diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic; 79644961713Sgirish if (diff < 0) 79744961713Sgirish diff += (1ll << 32); 79844961713Sgirish *pic0_data += diff; 79944961713Sgirish 80044961713Sgirish diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic; 80144961713Sgirish if (diff < 0) 80244961713Sgirish diff += (1ll << 32); 80344961713Sgirish *pic1_data += diff; 80444961713Sgirish 80544961713Sgirish pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK); 80644961713Sgirish pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT); 80744961713Sgirish } 80844961713Sgirish 80944961713Sgirish static void 81044961713Sgirish ni2_pcbe_free(void *config) 81144961713Sgirish { 81244961713Sgirish kmem_free(config, sizeof (ni2_pcbe_config_t)); 81344961713Sgirish } 81444961713Sgirish 81544961713Sgirish 81644961713Sgirish static struct modlpcbe modlpcbe = { 81744961713Sgirish &mod_pcbeops, 81859ac0c16Sdavemq #if defined(NIAGARA2_IMPL) 819820c9f58Skk208521 "UltraSPARC T2 Performance Counters", 82059ac0c16Sdavemq #elif defined(VFALLS_IMPL) 821820c9f58Skk208521 "UltraSPARC T2+ Performance Counters", 8224df55fdeSJanie Lu #elif defined(KT_IMPL) 823*c4c6ba57SVivek Gavaskar "SPARC T3 Performance Counters", 82459ac0c16Sdavemq #endif 82544961713Sgirish &ni2_pcbe_ops 82644961713Sgirish }; 82744961713Sgirish 82844961713Sgirish static struct modlinkage modl = { 82944961713Sgirish MODREV_1, 83044961713Sgirish &modlpcbe, 83144961713Sgirish }; 83244961713Sgirish 83344961713Sgirish int 83444961713Sgirish _init(void) 83544961713Sgirish { 83644961713Sgirish if (ni2_pcbe_init() != 0) 83744961713Sgirish return (ENOTSUP); 83844961713Sgirish return (mod_install(&modl)); 83944961713Sgirish } 84044961713Sgirish 84144961713Sgirish int 84244961713Sgirish _fini(void) 84344961713Sgirish { 84444961713Sgirish return (mod_remove(&modl)); 84544961713Sgirish } 84644961713Sgirish 84744961713Sgirish int 84844961713Sgirish _info(struct modinfo *mi) 84944961713Sgirish { 85044961713Sgirish return (mod_info(&modl, mi)); 85144961713Sgirish } 852