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
ni2_pcbe_init(void)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
ni2_pcbe_ncounters(void)33044961713Sgirish ni2_pcbe_ncounters(void)
33144961713Sgirish {
33244961713Sgirish return (2);
33344961713Sgirish }
33444961713Sgirish
33544961713Sgirish static const char *
ni2_pcbe_impl_name(void)33644961713Sgirish ni2_pcbe_impl_name(void)
33744961713Sgirish {
33859ac0c16Sdavemq return (cpu_impl_name);
33944961713Sgirish }
34044961713Sgirish
34144961713Sgirish static const char *
ni2_pcbe_cpuref(void)34244961713Sgirish ni2_pcbe_cpuref(void)
34344961713Sgirish {
34459ac0c16Sdavemq return (cpu_pcbe_ref);
34544961713Sgirish }
34644961713Sgirish
34744961713Sgirish static char *
ni2_pcbe_list_events(uint_t picnum)34844961713Sgirish ni2_pcbe_list_events(uint_t picnum)
34944961713Sgirish {
35044961713Sgirish ASSERT(picnum < cpc_ncounters);
35144961713Sgirish
35244961713Sgirish return (evlist);
35344961713Sgirish }
35444961713Sgirish
35544961713Sgirish static char *
ni2_pcbe_list_attrs(void)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 *
find_generic_event(char * name)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 *
find_event(char * name)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
ni2_pcbe_event_coverage(char * event)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
ni2_pcbe_overflow_bitmap(void)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
ni2_pcbe_configure(uint_t picnum,char * event,uint64_t preset,uint32_t flags,uint_t nattrs,kcpc_attr_t * attrs,void ** data,void * token)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
ni2_pcbe_program(void * token)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
ni2_pcbe_allstop(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
ni2_pcbe_sample(void * token)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
ni2_pcbe_free(void * config)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
_init(void)83444961713Sgirish _init(void)
83544961713Sgirish {
83644961713Sgirish if (ni2_pcbe_init() != 0)
83744961713Sgirish return (ENOTSUP);
83844961713Sgirish return (mod_install(&modl));
83944961713Sgirish }
84044961713Sgirish
84144961713Sgirish int
_fini(void)84244961713Sgirish _fini(void)
84344961713Sgirish {
84444961713Sgirish return (mod_remove(&modl));
84544961713Sgirish }
84644961713Sgirish
84744961713Sgirish int
_info(struct modinfo * mi)84844961713Sgirish _info(struct modinfo *mi)
84944961713Sgirish {
85044961713Sgirish return (mod_info(&modl, mi));
85144961713Sgirish }
852