xref: /titanic_51/usr/src/uts/sun4v/pcbe/niagara_pcbe.c (revision 4df55fde49134f9735f84011f23a767c75e393c7)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5820c9f58Skk208521  * Common Development and Distribution License (the "License").
6820c9f58Skk208521  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2267b48423SJonathan Haslam  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
27c7a079a8SJonathan Haslam  * This file contains preset event names from the Performance Application
28c7a079a8SJonathan Haslam  * Programming Interface v3.5 which included the following notice:
29c7a079a8SJonathan Haslam  *
30c7a079a8SJonathan Haslam  *                             Copyright (c) 2005,6
31c7a079a8SJonathan Haslam  *                           Innovative Computing Labs
32c7a079a8SJonathan Haslam  *                         Computer Science Department,
33c7a079a8SJonathan Haslam  *                            University of Tennessee,
34c7a079a8SJonathan Haslam  *                                 Knoxville, TN.
35c7a079a8SJonathan Haslam  *                              All Rights Reserved.
36c7a079a8SJonathan Haslam  *
37c7a079a8SJonathan Haslam  *
38c7a079a8SJonathan Haslam  * Redistribution and use in source and binary forms, with or without
39c7a079a8SJonathan Haslam  * modification, are permitted provided that the following conditions are met:
40c7a079a8SJonathan Haslam  *
41c7a079a8SJonathan Haslam  *    * Redistributions of source code must retain the above copyright notice,
42c7a079a8SJonathan Haslam  *      this list of conditions and the following disclaimer.
43c7a079a8SJonathan Haslam  *    * Redistributions in binary form must reproduce the above copyright
44c7a079a8SJonathan Haslam  *      notice, this list of conditions and the following disclaimer in the
45c7a079a8SJonathan Haslam  *      documentation and/or other materials provided with the distribution.
46c7a079a8SJonathan Haslam  *    * Neither the name of the University of Tennessee nor the names of its
47c7a079a8SJonathan Haslam  *      contributors may be used to endorse or promote products derived from
48c7a079a8SJonathan Haslam  *      this software without specific prior written permission.
49c7a079a8SJonathan Haslam  *
50c7a079a8SJonathan Haslam  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51c7a079a8SJonathan Haslam  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52c7a079a8SJonathan Haslam  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53c7a079a8SJonathan Haslam  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54c7a079a8SJonathan Haslam  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55c7a079a8SJonathan Haslam  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56c7a079a8SJonathan Haslam  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57c7a079a8SJonathan Haslam  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58c7a079a8SJonathan Haslam  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59c7a079a8SJonathan Haslam  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60c7a079a8SJonathan Haslam  * POSSIBILITY OF SUCH DAMAGE.
61c7a079a8SJonathan Haslam  *
62c7a079a8SJonathan Haslam  *
63c7a079a8SJonathan Haslam  * This open source software license conforms to the BSD License template.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate 
66c7a079a8SJonathan Haslam /*
67c7a079a8SJonathan Haslam  * Niagara Performance Counter Backend
68c7a079a8SJonathan Haslam  */
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
717c478bd9Sstevel@tonic-gate #include <sys/systm.h>
727c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
737c478bd9Sstevel@tonic-gate #include <sys/cpc_impl.h>
747c478bd9Sstevel@tonic-gate #include <sys/cpc_pcbe.h>
757c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
767c478bd9Sstevel@tonic-gate #include <sys/machsystm.h>
777c478bd9Sstevel@tonic-gate #include <sys/sdt.h>
787c478bd9Sstevel@tonic-gate #include <sys/niagararegs.h>
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate static int ni_pcbe_init(void);
817c478bd9Sstevel@tonic-gate static uint_t ni_pcbe_ncounters(void);
827c478bd9Sstevel@tonic-gate static const char *ni_pcbe_impl_name(void);
837c478bd9Sstevel@tonic-gate static const char *ni_pcbe_cpuref(void);
847c478bd9Sstevel@tonic-gate static char *ni_pcbe_list_events(uint_t picnum);
857c478bd9Sstevel@tonic-gate static char *ni_pcbe_list_attrs(void);
867c478bd9Sstevel@tonic-gate static uint64_t ni_pcbe_event_coverage(char *event);
877c478bd9Sstevel@tonic-gate static uint64_t ni_pcbe_overflow_bitmap(void);
887c478bd9Sstevel@tonic-gate static int ni_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
897c478bd9Sstevel@tonic-gate     uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
907c478bd9Sstevel@tonic-gate     void *token);
917c478bd9Sstevel@tonic-gate static void ni_pcbe_program(void *token);
927c478bd9Sstevel@tonic-gate static void ni_pcbe_allstop(void);
937c478bd9Sstevel@tonic-gate static void ni_pcbe_sample(void *token);
947c478bd9Sstevel@tonic-gate static void ni_pcbe_free(void *config);
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate extern void ultra_setpcr(uint64_t);
977c478bd9Sstevel@tonic-gate extern uint64_t ultra_getpcr(void);
987c478bd9Sstevel@tonic-gate extern void ultra_setpic(uint64_t);
997c478bd9Sstevel@tonic-gate extern uint64_t ultra_getpic(void);
1007c478bd9Sstevel@tonic-gate extern uint64_t ultra_gettick(void);
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate pcbe_ops_t ni_pcbe_ops = {
1037c478bd9Sstevel@tonic-gate 	PCBE_VER_1,
1047c478bd9Sstevel@tonic-gate 	CPC_CAP_OVERFLOW_INTERRUPT | CPC_CAP_OVERFLOW_PRECISE,
1057c478bd9Sstevel@tonic-gate 	ni_pcbe_ncounters,
1067c478bd9Sstevel@tonic-gate 	ni_pcbe_impl_name,
1077c478bd9Sstevel@tonic-gate 	ni_pcbe_cpuref,
1087c478bd9Sstevel@tonic-gate 	ni_pcbe_list_events,
1097c478bd9Sstevel@tonic-gate 	ni_pcbe_list_attrs,
1107c478bd9Sstevel@tonic-gate 	ni_pcbe_event_coverage,
1117c478bd9Sstevel@tonic-gate 	ni_pcbe_overflow_bitmap,
1127c478bd9Sstevel@tonic-gate 	ni_pcbe_configure,
1137c478bd9Sstevel@tonic-gate 	ni_pcbe_program,
1147c478bd9Sstevel@tonic-gate 	ni_pcbe_allstop,
1157c478bd9Sstevel@tonic-gate 	ni_pcbe_sample,
1167c478bd9Sstevel@tonic-gate 	ni_pcbe_free
1177c478bd9Sstevel@tonic-gate };
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate typedef struct _ni_pcbe_config {
1207c478bd9Sstevel@tonic-gate 	uint8_t		pcbe_picno;	/* 0 for pic0 or 1 for pic1 */
1217c478bd9Sstevel@tonic-gate 	uint32_t	pcbe_bits;	/* %pcr event code unshifted */
1227c478bd9Sstevel@tonic-gate 	uint32_t	pcbe_flags;	/* user/system/priv */
1237c478bd9Sstevel@tonic-gate 	uint32_t	pcbe_pic;	/* unshifted raw %pic value */
1247c478bd9Sstevel@tonic-gate } ni_pcbe_config_t;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate struct nametable {
1277c478bd9Sstevel@tonic-gate 	const uint8_t	bits;
1287c478bd9Sstevel@tonic-gate 	const char	*name;
1297c478bd9Sstevel@tonic-gate };
1307c478bd9Sstevel@tonic-gate 
131c7a079a8SJonathan Haslam typedef struct _ni_generic_events {
132c7a079a8SJonathan Haslam 	char *name;
133c7a079a8SJonathan Haslam 	char *event;
134c7a079a8SJonathan Haslam } ni_generic_event_t;
135c7a079a8SJonathan Haslam 
136*4df55fdeSJanie Lu #define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_PCR_PRIVPIC)
1377c478bd9Sstevel@tonic-gate #define	NT_END 0xFF
138c7a079a8SJonathan Haslam #define	GEN_EVT_END { NULL, NULL }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static const uint64_t   allstopped = ULTRA_PCR_PRIVPIC;
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate static const struct nametable Niagara_names1[] = {
1437c478bd9Sstevel@tonic-gate 	{0x00, "Instr_cnt"},
1447c478bd9Sstevel@tonic-gate 	{NT_END, ""}
1457c478bd9Sstevel@tonic-gate };
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate static const struct nametable Niagara_names0[] = {
1487c478bd9Sstevel@tonic-gate 	{0x0,	"SB_full"},
1497c478bd9Sstevel@tonic-gate 	{0x1,	"FP_instr_cnt"},
1507c478bd9Sstevel@tonic-gate 	{0x2,	"IC_miss"},
1517c478bd9Sstevel@tonic-gate 	{0x3,	"DC_miss"},
1527c478bd9Sstevel@tonic-gate 	{0x4,	"ITLB_miss"},
1537c478bd9Sstevel@tonic-gate 	{0x5,	"DTLB_miss"},
1547c478bd9Sstevel@tonic-gate 	{0x6,	"L2_imiss"},
1557c478bd9Sstevel@tonic-gate 	{0x7,	"L2_dmiss_ld"},
1567c478bd9Sstevel@tonic-gate 	{NT_END, ""}
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static const struct nametable *Niagara_names[2] = {
1607c478bd9Sstevel@tonic-gate 	Niagara_names0,
1617c478bd9Sstevel@tonic-gate 	Niagara_names1
1627c478bd9Sstevel@tonic-gate };
1637c478bd9Sstevel@tonic-gate 
164c7a079a8SJonathan Haslam static const ni_generic_event_t Niagara_generic_names1[] = {
165c7a079a8SJonathan Haslam 	{ "PAPI_tot_ins",	"Instr_cnt" },
166c7a079a8SJonathan Haslam 	{ NULL,			NULL }
167c7a079a8SJonathan Haslam };
168c7a079a8SJonathan Haslam 
169c7a079a8SJonathan Haslam static const ni_generic_event_t Niagara_generic_names0[] = {
170c7a079a8SJonathan Haslam 	{ "PAPI_l2_icm",	"L2_imiss" },
171c7a079a8SJonathan Haslam 	{ "PAPI_l2_ldm",	"L2_dmiss_ld" },
172c7a079a8SJonathan Haslam 	{ "PAPI_fp_ops",	"FP_instr_cnt" },
17367b48423SJonathan Haslam 	{ "PAPI_fp_ins",	"FP_instr_cnt" },
174c7a079a8SJonathan Haslam 	{ "PAPI_l1_icm",	"IC_miss" },
175c7a079a8SJonathan Haslam 	{ "PAPI_l1_dcm",	"DC_miss" },
176c7a079a8SJonathan Haslam 	{ "PAPI_tlb_im",	"ITLB_miss" },
177c7a079a8SJonathan Haslam 	{ "PAPI_tlb_dm",	"DTLB_miss" },
178c7a079a8SJonathan Haslam 	{ NULL,			NULL }
179c7a079a8SJonathan Haslam };
180c7a079a8SJonathan Haslam 
181c7a079a8SJonathan Haslam static const ni_generic_event_t *Niagara_generic_names[2] = {
182c7a079a8SJonathan Haslam 	Niagara_generic_names0,
183c7a079a8SJonathan Haslam 	Niagara_generic_names1
184c7a079a8SJonathan Haslam };
185c7a079a8SJonathan Haslam 
1867c478bd9Sstevel@tonic-gate static const struct nametable **events;
187c7a079a8SJonathan Haslam static const ni_generic_event_t **generic_events;
1887c478bd9Sstevel@tonic-gate static const char *ni_impl_name = "UltraSPARC T1";
1897c478bd9Sstevel@tonic-gate static char *pic_events[2];
1907c478bd9Sstevel@tonic-gate static uint16_t pcr_pic0_mask;
1917c478bd9Sstevel@tonic-gate static uint16_t pcr_pic1_mask;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate #define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
1947c478bd9Sstevel@tonic-gate 			"http://www.sun.com/processors/manuals"
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate static const char *niagara_cpuref = "See the \"UltraSPARC T1 User's Manual\" "
1977c478bd9Sstevel@tonic-gate 			"for descriptions of these events." CPU_REF_URL;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate static int
2007c478bd9Sstevel@tonic-gate ni_pcbe_init(void)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	const struct nametable		*n;
203c7a079a8SJonathan Haslam 	const ni_generic_event_t	*gevp;
2047c478bd9Sstevel@tonic-gate 	int				i;
2057c478bd9Sstevel@tonic-gate 	size_t				size;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	events = Niagara_names;
208c7a079a8SJonathan Haslam 	generic_events = Niagara_generic_names;
209*4df55fdeSJanie Lu 	pcr_pic0_mask = CPC_PCR_PIC0_MASK;
210*4df55fdeSJanie Lu 	pcr_pic1_mask = CPC_PCR_PIC1_MASK;
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	/*
2137c478bd9Sstevel@tonic-gate 	 * Initialize the list of events for each PIC.
2147c478bd9Sstevel@tonic-gate 	 * Do two passes: one to compute the size necessary and another
2157c478bd9Sstevel@tonic-gate 	 * to copy the strings. Need room for event, comma, and NULL terminator.
2167c478bd9Sstevel@tonic-gate 	 */
2177c478bd9Sstevel@tonic-gate 	for (i = 0; i < 2; i++) {
2187c478bd9Sstevel@tonic-gate 		size = 0;
2197c478bd9Sstevel@tonic-gate 		for (n = events[i]; n->bits != NT_END; n++)
2207c478bd9Sstevel@tonic-gate 			size += strlen(n->name) + 1;
221c7a079a8SJonathan Haslam 		for (gevp = generic_events[i]; gevp->name != NULL; gevp++)
222c7a079a8SJonathan Haslam 			size += strlen(gevp->name) + 1;
2237c478bd9Sstevel@tonic-gate 		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
2247c478bd9Sstevel@tonic-gate 		*pic_events[i] = '\0';
2257c478bd9Sstevel@tonic-gate 		for (n = events[i]; n->bits != NT_END; n++) {
2267c478bd9Sstevel@tonic-gate 			(void) strcat(pic_events[i], n->name);
2277c478bd9Sstevel@tonic-gate 			(void) strcat(pic_events[i], ",");
2287c478bd9Sstevel@tonic-gate 		}
229c7a079a8SJonathan Haslam 		for (gevp = generic_events[i]; gevp->name != NULL; gevp++) {
230c7a079a8SJonathan Haslam 			(void) strcat(pic_events[i], gevp->name);
231c7a079a8SJonathan Haslam 			(void) strcat(pic_events[i], ",");
232c7a079a8SJonathan Haslam 		}
2337c478bd9Sstevel@tonic-gate 		/*
2347c478bd9Sstevel@tonic-gate 		 * Remove trailing comma.
2357c478bd9Sstevel@tonic-gate 		 */
2367c478bd9Sstevel@tonic-gate 		pic_events[i][size - 1] = '\0';
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	return (0);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate static uint_t
2437c478bd9Sstevel@tonic-gate ni_pcbe_ncounters(void)
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	return (2);
2467c478bd9Sstevel@tonic-gate }
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate static const char *
2497c478bd9Sstevel@tonic-gate ni_pcbe_impl_name(void)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate 	return (ni_impl_name);
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate static const char *
2557c478bd9Sstevel@tonic-gate ni_pcbe_cpuref(void)
2567c478bd9Sstevel@tonic-gate {
2577c478bd9Sstevel@tonic-gate 	return (niagara_cpuref);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate static char *
2617c478bd9Sstevel@tonic-gate ni_pcbe_list_events(uint_t picnum)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	return (pic_events[picnum]);
2667c478bd9Sstevel@tonic-gate }
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static char *
2697c478bd9Sstevel@tonic-gate ni_pcbe_list_attrs(void)
2707c478bd9Sstevel@tonic-gate {
2717c478bd9Sstevel@tonic-gate 	return ("");
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
274c7a079a8SJonathan Haslam static const ni_generic_event_t *
275c7a079a8SJonathan Haslam find_generic_event(int regno, char *name)
276c7a079a8SJonathan Haslam {
277c7a079a8SJonathan Haslam 	const ni_generic_event_t *gevp;
278c7a079a8SJonathan Haslam 
279c7a079a8SJonathan Haslam 	for (gevp = generic_events[regno]; gevp->name != NULL; gevp++) {
280c7a079a8SJonathan Haslam 		if (strcmp(gevp->name, name) == 0)
281c7a079a8SJonathan Haslam 			return (gevp);
282c7a079a8SJonathan Haslam 	}
283c7a079a8SJonathan Haslam 
284c7a079a8SJonathan Haslam 	return (NULL);
285c7a079a8SJonathan Haslam }
286c7a079a8SJonathan Haslam 
2877c478bd9Sstevel@tonic-gate static const struct nametable *
2887c478bd9Sstevel@tonic-gate find_event(int regno, char *name)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	const struct nametable		*n;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	n = events[regno];
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	for (; n->bits != NT_END; n++)
2957c478bd9Sstevel@tonic-gate 		if (strcmp(name, n->name) == 0)
2967c478bd9Sstevel@tonic-gate 			return (n);
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	return (NULL);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate static uint64_t
3027c478bd9Sstevel@tonic-gate ni_pcbe_event_coverage(char *event)
3037c478bd9Sstevel@tonic-gate {
3047c478bd9Sstevel@tonic-gate 	uint64_t bitmap = 0;
3057c478bd9Sstevel@tonic-gate 
306c7a079a8SJonathan Haslam 	if ((find_event(0, event) != NULL) ||
307c7a079a8SJonathan Haslam 	    (find_generic_event(0, event) != NULL))
3087c478bd9Sstevel@tonic-gate 		bitmap = 0x1;
309c7a079a8SJonathan Haslam 	if ((find_event(1, event) != NULL) ||
310c7a079a8SJonathan Haslam 	    (find_generic_event(1, event) != NULL))
3117c478bd9Sstevel@tonic-gate 		bitmap |= 0x2;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	return (bitmap);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate /*
3177c478bd9Sstevel@tonic-gate  * These processors cannot tell which counter overflowed. The PCBE interface
3187c478bd9Sstevel@tonic-gate  * requires such processors to act as if _all_ counters had overflowed.
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate static uint64_t
3217c478bd9Sstevel@tonic-gate ni_pcbe_overflow_bitmap(void)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	uint64_t pcr, overflow;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	pcr = ultra_getpcr();
3267c478bd9Sstevel@tonic-gate 	DTRACE_PROBE1(niagara__getpcr, uint64_t, pcr);
327*4df55fdeSJanie Lu 	overflow =  (pcr & CPC_PCR_OVF_MASK) >>
328*4df55fdeSJanie Lu 	    CPC_PCR_OVF_SHIFT;
3297c478bd9Sstevel@tonic-gate #if 0
3307c478bd9Sstevel@tonic-gate 	/*
3317c478bd9Sstevel@tonic-gate 	 * Not needed if the CPC framework is responsible to stop counters
3327c478bd9Sstevel@tonic-gate 	 * and that action ends up clearing overflow flags.
3337c478bd9Sstevel@tonic-gate 	 */
3347c478bd9Sstevel@tonic-gate 	if (overflow)
335*4df55fdeSJanie Lu 		ultra_setpcr(pcr & ~CPC_PCR_OVF_MASK);
3367c478bd9Sstevel@tonic-gate #endif
3377c478bd9Sstevel@tonic-gate 	return (overflow);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3417c478bd9Sstevel@tonic-gate static int
3427c478bd9Sstevel@tonic-gate ni_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
3437c478bd9Sstevel@tonic-gate     uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t		*conf;
3467c478bd9Sstevel@tonic-gate 	const struct nametable		*n;
347c7a079a8SJonathan Haslam 	const ni_generic_event_t	*gevp;
3487c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t		*other_config;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/*
3517c478bd9Sstevel@tonic-gate 	 * If we've been handed an existing configuration, we need only preset
3527c478bd9Sstevel@tonic-gate 	 * the counter value.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	if (*data != NULL) {
3557c478bd9Sstevel@tonic-gate 		conf = *data;
3567c478bd9Sstevel@tonic-gate 		conf->pcbe_pic = (uint32_t)preset;
3577c478bd9Sstevel@tonic-gate 		return (0);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	if (picnum < 0 || picnum > 1)
3607c478bd9Sstevel@tonic-gate 		return (CPC_INVALID_PICNUM);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	if (nattrs != 0)
3637c478bd9Sstevel@tonic-gate 		return (CPC_INVALID_ATTRIBUTE);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/*
3667c478bd9Sstevel@tonic-gate 	 * Find other requests that will be programmed with this one, and ensure
3677c478bd9Sstevel@tonic-gate 	 * the flags don't conflict.
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
3707c478bd9Sstevel@tonic-gate 	    (other_config->pcbe_flags != flags))
3717c478bd9Sstevel@tonic-gate 		return (CPC_CONFLICTING_REQS);
3727c478bd9Sstevel@tonic-gate 
373c7a079a8SJonathan Haslam 	if ((n = find_event(picnum, event)) == NULL) {
374c7a079a8SJonathan Haslam 		if ((gevp = find_generic_event(picnum, event)) != NULL) {
375c7a079a8SJonathan Haslam 			n = find_event(picnum, gevp->event);
376c7a079a8SJonathan Haslam 			ASSERT(n != NULL);
377c7a079a8SJonathan Haslam 		} else {
3787c478bd9Sstevel@tonic-gate 			return (CPC_INVALID_EVENT);
379c7a079a8SJonathan Haslam 		}
380c7a079a8SJonathan Haslam 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	conf = kmem_alloc(sizeof (ni_pcbe_config_t), KM_SLEEP);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	conf->pcbe_picno = picnum;
3857c478bd9Sstevel@tonic-gate 	conf->pcbe_bits = (uint32_t)n->bits;
3867c478bd9Sstevel@tonic-gate 	conf->pcbe_flags = flags;
3877c478bd9Sstevel@tonic-gate 	conf->pcbe_pic = (uint32_t)preset;
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	*data = conf;
3907c478bd9Sstevel@tonic-gate 	return (0);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate static void
3947c478bd9Sstevel@tonic-gate ni_pcbe_program(void *token)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*pic0;
3977c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*pic1;
3987c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*tmp;
3997c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	empty = { 1, 0x1c, 0, 0 }; /* SW_count_1 */
4007c478bd9Sstevel@tonic-gate 	uint64_t		pcr;
4017c478bd9Sstevel@tonic-gate 	uint64_t		curpic;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	if ((pic0 = (ni_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
4047c478bd9Sstevel@tonic-gate 	    NULL)
4057c478bd9Sstevel@tonic-gate 		panic("ni_pcbe: token %p has no configs", token);
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
4087c478bd9Sstevel@tonic-gate 		pic1 = &empty;
4097c478bd9Sstevel@tonic-gate 		empty.pcbe_flags = pic0->pcbe_flags;
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_picno != 0) {
4137c478bd9Sstevel@tonic-gate 		/*
4147c478bd9Sstevel@tonic-gate 		 * pic0 is counter 1, so if we need the empty config it should
4157c478bd9Sstevel@tonic-gate 		 * be counter 0.
4167c478bd9Sstevel@tonic-gate 		 */
4177c478bd9Sstevel@tonic-gate 		empty.pcbe_picno = 0;
4187c478bd9Sstevel@tonic-gate #if 0
4197c478bd9Sstevel@tonic-gate 		/* no selection for counter 0 */
4207c478bd9Sstevel@tonic-gate 		empty.pcbe_bits = 0x14; /* SW_count_0 - won't overflow */
4217c478bd9Sstevel@tonic-gate #endif
4227c478bd9Sstevel@tonic-gate 		tmp = pic0;
4237c478bd9Sstevel@tonic-gate 		pic0 = pic1;
4247c478bd9Sstevel@tonic-gate 		pic1 = tmp;
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
4287c478bd9Sstevel@tonic-gate 		panic("ni_pcbe: bad config on token %p\n", token);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/*
4317c478bd9Sstevel@tonic-gate 	 * UltraSPARC does not allow pic0 to be configured differently
4327c478bd9Sstevel@tonic-gate 	 * from pic1. If the flags on these two configurations are
4337c478bd9Sstevel@tonic-gate 	 * different, they are incompatible. This condition should be
4347c478bd9Sstevel@tonic-gate 	 * caught at configure time.
4357c478bd9Sstevel@tonic-gate 	 */
4367c478bd9Sstevel@tonic-gate 	ASSERT(pic0->pcbe_flags == pic1->pcbe_flags);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	ultra_setpcr(allstopped);
4397c478bd9Sstevel@tonic-gate 	ultra_setpic(((uint64_t)pic1->pcbe_pic << PIC1_SHIFT) |
4407c478bd9Sstevel@tonic-gate 	    (uint64_t)pic0->pcbe_pic);
4417c478bd9Sstevel@tonic-gate 
442*4df55fdeSJanie Lu 	pcr = (pic0->pcbe_bits & pcr_pic0_mask) << CPC_PCR_PIC0_SHIFT;
443*4df55fdeSJanie Lu 	pcr |= (pic1->pcbe_bits & pcr_pic1_mask) << CPC_PCR_PIC1_SHIFT;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_flags & CPC_COUNT_USER)
446*4df55fdeSJanie Lu 		pcr |= (1ull << CPC_PCR_USR);
4477c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_flags & CPC_COUNT_SYSTEM)
448*4df55fdeSJanie Lu 		pcr |= (1ull << CPC_PCR_SYS);
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	DTRACE_PROBE1(niagara__setpcr, uint64_t, pcr);
4517c478bd9Sstevel@tonic-gate 	ultra_setpcr(pcr);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/*
4547c478bd9Sstevel@tonic-gate 	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
4557c478bd9Sstevel@tonic-gate 	 * expect the value we wrote into the PIC, above, to be there after
4567c478bd9Sstevel@tonic-gate 	 * starting the counter. We must sample the counter value now and use
4577c478bd9Sstevel@tonic-gate 	 * that as the baseline for future samples.
4587c478bd9Sstevel@tonic-gate 	 */
4597c478bd9Sstevel@tonic-gate 	curpic = ultra_getpic();
4607c478bd9Sstevel@tonic-gate 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
4617c478bd9Sstevel@tonic-gate 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
4627c478bd9Sstevel@tonic-gate 	DTRACE_PROBE1(niagara__newpic, uint64_t, curpic);
4637c478bd9Sstevel@tonic-gate }
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate static void
4667c478bd9Sstevel@tonic-gate ni_pcbe_allstop(void)
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate 	ultra_setpcr(allstopped);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate static void
4737c478bd9Sstevel@tonic-gate ni_pcbe_sample(void *token)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate 	uint64_t		curpic;
4767c478bd9Sstevel@tonic-gate 	int64_t			diff;
4777c478bd9Sstevel@tonic-gate 	uint64_t		*pic0_data;
4787c478bd9Sstevel@tonic-gate 	uint64_t		*pic1_data;
4797c478bd9Sstevel@tonic-gate 	uint64_t		*dtmp;
4807c478bd9Sstevel@tonic-gate 	uint64_t		tmp;
4817c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*pic0;
4827c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*pic1;
4837c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	empty = { 1, 0, 0, 0 };
4847c478bd9Sstevel@tonic-gate 	ni_pcbe_config_t	*ctmp;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	curpic = ultra_getpic();
4877c478bd9Sstevel@tonic-gate 	DTRACE_PROBE1(niagara__getpic, uint64_t, curpic);
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
4907c478bd9Sstevel@tonic-gate 		panic("%s: token %p has no configs", ni_impl_name, token);
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
4937c478bd9Sstevel@tonic-gate 		pic1 = &empty;
4947c478bd9Sstevel@tonic-gate 		pic1_data = &tmp;
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_picno != 0) {
4987c478bd9Sstevel@tonic-gate 		empty.pcbe_picno = 0;
4997c478bd9Sstevel@tonic-gate 		ctmp = pic0;
5007c478bd9Sstevel@tonic-gate 		pic0 = pic1;
5017c478bd9Sstevel@tonic-gate 		pic1 = ctmp;
5027c478bd9Sstevel@tonic-gate 		dtmp = pic0_data;
5037c478bd9Sstevel@tonic-gate 		pic0_data = pic1_data;
5047c478bd9Sstevel@tonic-gate 		pic1_data = dtmp;
5057c478bd9Sstevel@tonic-gate 	}
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (pic0->pcbe_picno != 0 || pic1->pcbe_picno != 1)
5087c478bd9Sstevel@tonic-gate 		panic("%s: bad config on token %p\n", ni_impl_name, token);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->pcbe_pic;
5117c478bd9Sstevel@tonic-gate 	if (diff < 0)
5127c478bd9Sstevel@tonic-gate 		diff += (1ll << 32);
5137c478bd9Sstevel@tonic-gate 	*pic0_data += diff;
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate 	diff = (curpic >> 32) - (uint64_t)pic1->pcbe_pic;
5167c478bd9Sstevel@tonic-gate 	if (diff < 0)
5177c478bd9Sstevel@tonic-gate 		diff += (1ll << 32);
5187c478bd9Sstevel@tonic-gate 	*pic1_data += diff;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	pic0->pcbe_pic = (uint32_t)(curpic & PIC0_MASK);
5217c478bd9Sstevel@tonic-gate 	pic1->pcbe_pic = (uint32_t)(curpic >> PIC1_SHIFT);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate static void
5257c478bd9Sstevel@tonic-gate ni_pcbe_free(void *config)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate 	kmem_free(config, sizeof (ni_pcbe_config_t));
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate static struct modlpcbe modlpcbe = {
5327c478bd9Sstevel@tonic-gate 	&mod_pcbeops,
533820c9f58Skk208521 	"UltraSPARC T1 Performance Counters",
5347c478bd9Sstevel@tonic-gate 	&ni_pcbe_ops
5357c478bd9Sstevel@tonic-gate };
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate static struct modlinkage modl = {
5387c478bd9Sstevel@tonic-gate 	MODREV_1,
5397c478bd9Sstevel@tonic-gate 	&modlpcbe,
5407c478bd9Sstevel@tonic-gate };
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate int
5437c478bd9Sstevel@tonic-gate _init(void)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	if (ni_pcbe_init() != 0)
5467c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
5477c478bd9Sstevel@tonic-gate 	return (mod_install(&modl));
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate int
5517c478bd9Sstevel@tonic-gate _fini(void)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	return (mod_remove(&modl));
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate int
5577c478bd9Sstevel@tonic-gate _info(struct modinfo *mi)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate 	return (mod_info(&modl, mi));
5607c478bd9Sstevel@tonic-gate }
561