us234_pcbe.c revision 7640:c468bb5b1d2d
1258945Sroberto/*
2258945Sroberto * CDDL HEADER START
3258945Sroberto *
4258945Sroberto * The contents of this file are subject to the terms of the
5258945Sroberto * Common Development and Distribution License (the "License").
6258945Sroberto * You may not use this file except in compliance with the License.
7258945Sroberto *
8258945Sroberto * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9258945Sroberto * or http://www.opensolaris.org/os/licensing.
10258945Sroberto * See the License for the specific language governing permissions
11258945Sroberto * and limitations under the License.
12258945Sroberto *
13258945Sroberto * When distributing Covered Code, include this CDDL HEADER in each
14258945Sroberto * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15258945Sroberto * If applicable, add the following below this CDDL HEADER, with the
16258945Sroberto * fields enclosed by brackets "[]" replaced with your own identifying
17258945Sroberto * information: Portions Copyright [yyyy] [name of copyright owner]
18258945Sroberto *
19258945Sroberto * CDDL HEADER END
20258945Sroberto */
21258945Sroberto/*
22258945Sroberto * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23258945Sroberto * Use is subject to license terms.
24258945Sroberto */
25258945Sroberto
26258945Sroberto/*
27258945Sroberto * This file contains preset event names from the Performance Application
28258945Sroberto * Programming Interface v3.5 which included the following notice:
29258945Sroberto *
30258945Sroberto *                             Copyright (c) 2005,6
31258945Sroberto *                           Innovative Computing Labs
32258945Sroberto *                         Computer Science Department,
33258945Sroberto *                            University of Tennessee,
34258945Sroberto *                                 Knoxville, TN.
35258945Sroberto *                              All Rights Reserved.
36258945Sroberto *
37258945Sroberto *
38258945Sroberto * Redistribution and use in source and binary forms, with or without
39258945Sroberto * modification, are permitted provided that the following conditions are met:
40258945Sroberto *
41258945Sroberto *    * Redistributions of source code must retain the above copyright notice,
42258945Sroberto *      this list of conditions and the following disclaimer.
43258945Sroberto *    * Redistributions in binary form must reproduce the above copyright
44258945Sroberto *      notice, this list of conditions and the following disclaimer in the
45258945Sroberto *      documentation and/or other materials provided with the distribution.
46258945Sroberto *    * Neither the name of the University of Tennessee nor the names of its
47258945Sroberto *      contributors may be used to endorse or promote products derived from
48258945Sroberto *      this software without specific prior written permission.
49258945Sroberto *
50258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51258945Sroberto * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53258945Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54258945Sroberto * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55258945Sroberto * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56258945Sroberto * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57258945Sroberto * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58258945Sroberto * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59258945Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60258945Sroberto * POSSIBILITY OF SUCH DAMAGE.
61258945Sroberto *
62258945Sroberto *
63258945Sroberto * This open source software license conforms to the BSD License template.
64258945Sroberto */
65258945Sroberto
66258945Sroberto/*
67258945Sroberto * UltraSPARC Performance Counter Backend
68258945Sroberto */
69258945Sroberto
70258945Sroberto#include <sys/cpuvar.h>
71258945Sroberto#include <sys/systm.h>
72258945Sroberto#include <sys/cmn_err.h>
73258945Sroberto#include <sys/spitregs.h>
74258945Sroberto#include <sys/cheetahregs.h>
75258945Sroberto#include <sys/cpc_impl.h>
76258945Sroberto#include <sys/cpc_pcbe.h>
77258945Sroberto#include <sys/modctl.h>
78258945Sroberto#include <sys/machsystm.h>
79258945Sroberto#include <sys/sdt.h>
80258945Sroberto
81258945Srobertostatic int us_pcbe_init(void);
82258945Srobertostatic uint_t us_pcbe_ncounters(void);
83258945Srobertostatic const char *us_pcbe_impl_name(void);
84258945Srobertostatic const char *us_pcbe_cpuref(void);
85258945Srobertostatic char *us_pcbe_list_events(uint_t picnum);
86static char *us_pcbe_list_attrs(void);
87static uint64_t us_pcbe_event_coverage(char *event);
88static uint64_t us_pcbe_overflow_bitmap(void);
89static int us_pcbe_configure(uint_t picnum, char *event, uint64_t preset,
90    uint32_t flags, uint_t nattrs, kcpc_attr_t *attrs, void **data,
91    void *token);
92static void us_pcbe_program(void *token);
93static void us_pcbe_allstop(void);
94static void us_pcbe_sample(void *token);
95static void us_pcbe_free(void *config);
96
97extern void ultra_setpcr(uint64_t);
98extern uint64_t ultra_getpcr(void);
99extern void ultra_setpic(uint64_t);
100extern uint64_t ultra_getpic(void);
101extern uint64_t ultra_gettick(void);
102
103pcbe_ops_t us_pcbe_ops = {
104	PCBE_VER_1,
105	CPC_CAP_OVERFLOW_INTERRUPT,
106	us_pcbe_ncounters,
107	us_pcbe_impl_name,
108	us_pcbe_cpuref,
109	us_pcbe_list_events,
110	us_pcbe_list_attrs,
111	us_pcbe_event_coverage,
112	us_pcbe_overflow_bitmap,
113	us_pcbe_configure,
114	us_pcbe_program,
115	us_pcbe_allstop,
116	us_pcbe_sample,
117	us_pcbe_free
118};
119
120typedef struct _us_pcbe_config {
121	uint8_t		us_picno;	/* 0 for pic0 or 1 for pic1 */
122	uint32_t	us_bits;	/* %pcr event code unshifted */
123	uint32_t	us_flags;	/* user/system/priv */
124	uint32_t	us_pic;		/* unshifted raw %pic value */
125} us_pcbe_config_t;
126
127struct nametable {
128	const uint8_t	bits;
129	const char	*name;
130};
131
132typedef struct _us_generic_event {
133	char *name;
134	char *event;
135} us_generic_event_t;
136
137#define	PIC0_MASK (((uint64_t)1 << 32) - 1)
138
139#define	ULTRA_PCR_SYS		(UINT64_C(1) << CPC_ULTRA_PCR_SYS)
140#define	ULTRA_PCR_PRIVPIC	(UINT64_C(1) << CPC_ULTRA_PCR_PRIVPIC)
141
142#define	CPC_ULTRA_PCR_USR		2
143#define	CPC_ULTRA_PCR_SYS		1
144#define	CPC_ULTRA_PCR_PRIVPIC		0
145
146#define	CPC_ULTRA_PCR_PIC0_SHIFT	4
147#define	CPC_ULTRA2_PCR_PIC_MASK		UINT64_C(0xf)
148#define	CPC_ULTRA3_PCR_PIC_MASK		UINT64_C(0x3f)
149#define	CPC_ULTRA_PCR_PIC1_SHIFT	11
150
151#define	NT_END 0xFF
152#define	CPC_GEN_END { NULL, NULL }
153
154static const uint64_t   allstopped = ULTRA_PCR_PRIVPIC;
155
156#define	USall_EVENTS_0						\
157	{0x0,	"Cycle_cnt"},					\
158	{0x1,	"Instr_cnt"},					\
159	{0x2,	"Dispatch0_IC_miss"},				\
160	{0x8,	"IC_ref"},					\
161	{0x9,	"DC_rd"},					\
162	{0xa,	"DC_wr"},					\
163	{0xc,	"EC_ref"},					\
164	{0xe,	"EC_snoop_inv"}
165
166static const struct nametable US12_names0[] = {
167	USall_EVENTS_0,
168	{0x3,	"Dispatch0_storeBuf"},
169	{0xb,	"Load_use"},
170	{0xd,	"EC_write_hit_RDO"},
171	{0xf,	"EC_rd_hit"},
172	{NT_END, ""}
173};
174
175#define	US3all_EVENTS_0						\
176	{0x3,	"Dispatch0_br_target"},				\
177	{0x4,	"Dispatch0_2nd_br"},				\
178	{0x5,	"Rstall_storeQ"},				\
179	{0x6,	"Rstall_IU_use"},				\
180	{0xd,	"EC_write_hit_RTO"},				\
181	{0xf,	"EC_rd_miss"},					\
182	{0x10,	"PC_port0_rd"},					\
183	{0x11,	"SI_snoop"},					\
184	{0x12,	"SI_ciq_flow"},					\
185	{0x13,	"SI_owned"},					\
186	{0x14,	"SW_count_0"},					\
187	{0x15,	"IU_Stat_Br_miss_taken"},			\
188	{0x16,	"IU_Stat_Br_count_taken"},			\
189	{0x17,	"Dispatch_rs_mispred"},				\
190	{0x18,	"FA_pipe_completion"}
191
192#define	US3_MC_EVENTS_0						\
193	{0x20,	"MC_reads_0"},					\
194	{0x21,	"MC_reads_1"},					\
195	{0x22,	"MC_reads_2"},					\
196	{0x23,	"MC_reads_3"},					\
197	{0x24,	"MC_stalls_0"},					\
198	{0x25,	"MC_stalls_2"}
199
200#define	US3_I_MC_EVENTS_0					\
201	{0x20,	"MC_read_dispatched"},				\
202	{0x21,	"MC_write_dispatched"},				\
203	{0x22,	"MC_read_returned_to_JBU"},			\
204	{0x23,	"MC_msl_busy_stall"},				\
205	{0x24,	"MC_mdb_overflow_stall"},			\
206	{0x25,	"MC_miu_spec_request"}
207
208#define	USall_EVENTS_1						\
209	{0x0,	"Cycle_cnt"},					\
210	{0x1,	"Instr_cnt"},					\
211	{0x2,	"Dispatch0_mispred"},				\
212	{0xd,	"EC_wb"},					\
213	{0xe,	"EC_snoop_cb"}
214
215static const struct nametable US3_names0[] = {
216	USall_EVENTS_0,
217	US3all_EVENTS_0,
218	US3_MC_EVENTS_0,
219	{NT_END, ""}
220};
221
222static const struct nametable US3_PLUS_names0[] = {
223	USall_EVENTS_0,
224	US3all_EVENTS_0,
225	US3_MC_EVENTS_0,
226	{0x19,	"EC_wb_remote"},
227	{0x1a,	"EC_miss_local"},
228	{0x1b,	"EC_miss_mtag_remote"},
229	{NT_END, ""}
230};
231
232static const struct nametable US3_I_names0[] = {
233	USall_EVENTS_0,
234	US3all_EVENTS_0,
235	US3_I_MC_EVENTS_0,
236	{NT_END, ""}
237};
238
239static const struct nametable US4_PLUS_names0[] = {
240	{0x0,   "Cycle_cnt"},
241	{0x1,   "Instr_cnt"},
242	{0x2,   "Dispatch0_IC_miss"},
243	{0x3,   "IU_stat_jmp_correct_pred"},
244	{0x4,   "Dispatch0_2nd_br"},
245	{0x5,   "Rstall_storeQ"},
246	{0x6,   "Rstall_IU_use"},
247	{0x7,   "IU_stat_ret_correct_pred"},
248	{0x8,   "IC_ref"},
249	{0x9,   "DC_rd"},
250	{0xa,   "Rstall_FP_use"},
251	{0xb,   "SW_pf_instr"},
252	{0xc,   "L2_ref"},
253	{0xd,   "L2_write_hit_RTO"},
254	{0xe,   "L2_snoop_inv_sh"},
255	{0xf,   "L2_rd_miss"},
256	{0x10,  "PC_rd"},
257	{0x11,  "SI_snoop_sh"},
258	{0x12,  "SI_ciq_flow_sh"},
259	{0x13,  "Re_DC_miss"},
260	{0x14,  "SW_count_NOP"},
261	{0x15,  "IU_stat_br_miss_taken"},
262	{0x16,  "IU_stat_br_count_untaken"},
263	{0x17,  "HW_pf_exec"},
264	{0x18,  "FA_pipe_completion"},
265	{0x19,  "SSM_L3_wb_remote"},
266	{0x1a,  "SSM_L3_miss_local"},
267	{0x1b,  "SSM_L3_miss_mtag_remote"},
268	{0x1c,  "SW_pf_str_trapped"},
269	{0x1d,  "SW_pf_PC_installed"},
270	{0x1e,  "IPB_to_IC_fill"},
271	{0x1f,  "L2_write_miss"},
272	{0x20,  "MC_reads_0_sh"},
273	{0x21,  "MC_reads_1_sh"},
274	{0x22,  "MC_reads_2_sh"},
275	{0x23,  "MC_reads_3_sh"},
276	{0x24,  "MC_stalls_0_sh"},
277	{0x25,  "MC_stalls_2_sh"},
278	{0x26,  "L2_hit_other_half"},
279	{0x28,  "L3_rd_miss"},
280	{0x29,  "Re_L2_miss"},
281	{0x2a,  "IC_miss_cancelled"},
282	{0x2b,  "DC_wr_miss"},
283	{0x2c,  "L3_hit_I_state_sh"},
284	{0x2d,  "SI_RTS_src_data"},
285	{0x2e,  "L2_IC_miss"},
286	{0x2f,  "SSM_new_transaction_sh"},
287	{0x30,  "L2_SW_pf_miss"},
288	{0x31,  "L2_wb"},
289	{0x32,  "L2_wb_sh"},
290	{0x33,  "L2_snoop_cb_sh"},
291	{NT_END, ""}
292};
293
294
295#define	US3all_EVENTS_1				\
296	{0x3,	"IC_miss_cancelled"},		\
297	{0x5,	"Re_FPU_bypass"},		\
298	{0x6,	"Re_DC_miss"},			\
299	{0x7,	"Re_EC_miss"},			\
300	{0x8,	"IC_miss"},			\
301	{0x9,	"DC_rd_miss"},			\
302	{0xa,	"DC_wr_miss"},			\
303	{0xb,	"Rstall_FP_use"},		\
304	{0xc,	"EC_misses"},			\
305	{0xf,	"EC_ic_miss"},			\
306	{0x10,	"Re_PC_miss"},			\
307	{0x11,	"ITLB_miss"},			\
308	{0x12,	"DTLB_miss"},			\
309	{0x13,	"WC_miss"},			\
310	{0x14,	"WC_snoop_cb"},			\
311	{0x15,	"WC_scrubbed"},			\
312	{0x16,	"WC_wb_wo_read"},		\
313	{0x18,	"PC_soft_hit"},			\
314	{0x19,	"PC_snoop_inv"},		\
315	{0x1a,	"PC_hard_hit"},			\
316	{0x1b,	"PC_port1_rd"},			\
317	{0x1c,	"SW_count_1"},			\
318	{0x1d,	"IU_Stat_Br_miss_untaken"},	\
319	{0x1e,	"IU_Stat_Br_count_untaken"},	\
320	{0x1f,	"PC_MS_misses"},		\
321	{0x26,	"Re_RAW_miss"},			\
322	{0x27,	"FM_pipe_completion"}
323
324#define	US3_MC_EVENTS_1				\
325	{0x20,	"MC_writes_0"},			\
326	{0x21,	"MC_writes_1"},			\
327	{0x22,	"MC_writes_2"},			\
328	{0x23,	"MC_writes_3"},			\
329	{0x24,	"MC_stalls_1"},			\
330	{0x25,	"MC_stalls_3"}
331
332#define	US3_I_MC_EVENTS_1			\
333	{0x20,	"MC_open_bank_cmds"},		\
334	{0x21,	"MC_reads"},			\
335	{0x22,	"MC_writes"},			\
336	{0x23,	"MC_page_close_stall"}
337
338static const struct nametable US3_names1[] = {
339	USall_EVENTS_1,
340	US3all_EVENTS_1,
341	US3_MC_EVENTS_1,
342	{0x4,	"Re_endian_miss"},
343	{NT_END, ""}
344};
345
346static const struct nametable US3_PLUS_names1[] = {
347	USall_EVENTS_1,
348	US3all_EVENTS_1,
349	US3_MC_EVENTS_1,
350	{0x4,	"Re_DC_missovhd"},
351	{0x28,	"EC_miss_mtag_remote"},
352	{0x29,	"EC_miss_remote"},
353	{NT_END, ""}
354};
355
356static const struct nametable US3_I_names1[] = {
357	USall_EVENTS_1,
358	US3all_EVENTS_1,
359	US3_I_MC_EVENTS_1,
360	{0x4,	"Re_DC_missovhd"},
361	{NT_END, ""}
362};
363
364static const struct nametable US4_PLUS_names1[] = {
365	{0x0,   "Cycle_cnt"},
366	{0x1,   "Instr_cnt"},
367	{0x2,   "Dispatch0_other"},
368	{0x3,   "DC_wr"},
369	{0x4,   "Re_DC_missovhd"},
370	{0x5,   "Re_FPU_bypass"},
371	{0x6,   "L3_write_hit_RTO"},
372	{0x7,   "L2L3_snoop_inv_sh"},
373	{0x8,   "IC_L2_req"},
374	{0x9,   "DC_rd_miss"},
375	{0xa,   "L2_hit_I_state_sh"},
376	{0xb,   "L3_write_miss_RTO"},
377	{0xc,   "L2_miss"},
378	{0xd,   "SI_owned_sh"},
379	{0xe,   "SI_RTO_src_data"},
380	{0xf,   "SW_pf_duplicate"},
381	{0x10,  "IU_stat_jmp_mispred"},
382	{0x11,  "ITLB_miss"},
383	{0x12,  "DTLB_miss"},
384	{0x13,  "WC_miss"},
385	{0x14,  "IC_fill"},
386	{0x15,  "IU_stat_ret_mispred"},
387	{0x16,  "Re_L3_miss"},
388	{0x17,  "Re_PFQ_full"},
389	{0x18,  "PC_soft_hit"},
390	{0x19,  "PC_inv"},
391	{0x1a,  "PC_hard_hit"},
392	{0x1b,  "IC_pf"},
393	{0x1c,  "SW_count_NOP"},
394	{0x1d,  "IU_stat_br_miss_untaken"},
395	{0x1e,  "IU_stat_br_count_taken"},
396	{0x1f,  "PC_miss"},
397	{0x20,  "MC_writes_0_sh"},
398	{0x21,  "MC_writes_1_sh"},
399	{0x22,  "MC_writes_2_sh"},
400	{0x23,  "MC_writes_3_sh"},
401	{0x24,  "MC_stalls_1_sh"},
402	{0x25,  "MC_stalls_3_sh"},
403	{0x26,  "Re_RAW_miss"},
404	{0x27,  "FM_pipe_completion"},
405	{0x28,  "SSM_L3_miss_mtag_remote"},
406	{0x29,  "SSM_L3_miss_remote"},
407	{0x2a,  "SW_pf_exec"},
408	{0x2b,  "SW_pf_str_exec"},
409	{0x2c,  "SW_pf_dropped"},
410	{0x2d,  "SW_pf_L2_installed"},
411	{0x2f,  "L2_HW_pf_miss"},
412	{0x31,  "L3_miss"},
413	{0x32,  "L3_IC_miss"},
414	{0x33,  "L3_SW_pf_miss"},
415	{0x34,  "L3_hit_other_half"},
416	{0x35,  "L3_wb"},
417	{0x36,  "L3_wb_sh"},
418	{0x37,  "L2L3_snoop_cb_sh"},
419	{NT_END, ""}
420};
421
422static const struct nametable US12_names1[] = {
423	USall_EVENTS_1,
424	{0x3,	"Dispatch0_FP_use"},
425	{0x8,	"IC_hit"},
426	{0x9,	"DC_rd_hit"},
427	{0xa,	"DC_wr_hit"},
428	{0xb,	"Load_use_RAW"},
429	{0xc,	"EC_hit"},
430	{0xf,	"EC_ic_hit"},
431	{NT_END, ""}
432};
433
434static const struct nametable *US12_names[2] = {
435	US12_names0,
436	US12_names1
437};
438
439static const struct nametable *US3_names[2] = {
440	US3_names0,
441	US3_names1
442};
443
444static const struct nametable *US3_PLUS_names[2] = {
445	US3_PLUS_names0,
446	US3_PLUS_names1
447};
448
449static const struct nametable *US4_PLUS_names[2] = {
450	US4_PLUS_names0,
451	US4_PLUS_names1
452};
453
454static const struct nametable *US3_I_names[2] = {
455	US3_I_names0,
456	US3_I_names1
457};
458
459static const us_generic_event_t US12_generic_names0[] = {
460	{ "PAPI_tot_cyc",  "Cycle_cnt" },
461	{ "PAPI_tot_ins",  "Instr_cnt" },
462	{ "PAPI_tot_iis",  "Instr_cnt" },
463	{ "PAPI_l1_dcr",   "DC_rd" },
464	{ "PAPI_l1_dcw",   "DC_wr" },
465	{ "PAPI_l1_ica",   "IC_ref" },
466	{ "PAPI_l2_tca",   "EC_ref" },
467	{ "PAPI_l2_dch",   "EC_rd_hit" },
468	{ "PAPI_ca_inv",   "EC_snoop_inv" },
469	CPC_GEN_END
470};
471
472static const us_generic_event_t US12_generic_names1[] = {
473	{ "PAPI_tot_cyc",  "Cycle_cnt" },
474	{ "PAPI_tot_ins",  "Instr_cnt" },
475	{ "PAPI_tot_iis",  "Instr_cnt" },
476	{ "PAPI_br_msp",   "Dispatch0_mispred" },
477	{ "PAPI_ca_snp",   "EC_snoop_cb" },
478	{ "PAPI_l1_ich",   "IC_hit" },
479	{ "PAPI_l2_tch",   "EC_hit" },
480	{ "PAPI_l2_ich",   "EC_ic_hit" },
481	CPC_GEN_END
482};
483
484static const us_generic_event_t US3_generic_names0[] = {
485	{ "PAPI_tot_cyc",  "Cycle_cnt" },
486	{ "PAPI_tot_ins",  "Instr_cnt" },
487	{ "PAPI_tot_iis",  "Instr_cnt" },
488	{ "PAPI_fad_ins",  "FA_pipe_completion" },
489	{ "PAPI_l1_dcr",   "DC_rd" },
490	{ "PAPI_l1_dcw",   "DC_wr" },
491	{ "PAPI_l1_ica",   "IC_ref" },
492	{ "PAPI_l2_tca",   "EC_ref" },
493	{ "PAPI_l2_ldm",   "EC_rd_miss" },
494	{ "PAPI_ca_inv",   "EC_snoop_inv" },
495	{ "PAPI_br_tkn",   "IU_Stat_Br_count_taken" },
496	CPC_GEN_END
497};
498
499static const us_generic_event_t US3_generic_names1[] = {
500	{ "PAPI_tot_cyc",  "Cycle_cnt" },
501	{ "PAPI_tot_ins",  "Instr_cnt" },
502	{ "PAPI_tot_iis",  "Instr_cnt" },
503	{ "PAPI_fml_ins",  "FM_pipe_completion" },
504	{ "PAPI_l1_icm",   "IC_miss" },
505	{ "PAPI_l1_ldm",   "DC_rd_miss" },
506	{ "PAPI_l1_stm",   "DC_wr_miss" },
507	{ "PAPI_l2_tcm",   "EC_misses" },
508	{ "PAPI_l2_icm",   "EC_ic_miss" },
509	{ "PAPI_tlb_dm",   "DTLB_miss" },
510	{ "PAPI_tlb_im",   "ITLB_miss" },
511	{ "PAPI_br_ntk",   "IU_Stat_Br_count_untaken" },
512	{ "PAPI_br_msp",   "Dispatch0_mispred" },
513	{ "PAPI_ca_snp",   "EC_snoop_cb" },
514	CPC_GEN_END
515};
516
517static const us_generic_event_t US4_PLUS_generic_names0[] = {
518	{ "PAPI_tot_cyc",  "Cycle_cnt" },
519	{ "PAPI_tot_ins",  "Instr_cnt" },
520	{ "PAPI_tot_iis",  "Instr_cnt" },
521	{ "PAPI_fma_ins",  "FA_pipe_completion" },
522	{ "PAPI_l1_dcr",   "DC_rd" },
523	{ "PAPI_l1_stm",   "DC_wr_miss" },
524	{ "PAPI_l1_ica",   "IC_ref" },
525	{ "PAPI_l2_tca",   "L2_ref" },
526	{ "PAPI_l2_ldm",   "L2_rd_miss" },
527	{ "PAPI_l2_icm",   "L2_IC_miss" },
528	{ "PAPI_l2_stm",   "L2_write_miss" },
529	{ "PAPI_l3_ldm",   "L3_rd_miss" },
530	{ "PAPI_br_ntk",   "IU_stat_br_count_untaken" },
531	CPC_GEN_END
532};
533
534static const us_generic_event_t US4_PLUS_generic_names1[] = {
535	{ "PAPI_tot_cyc", "Cycle_cnt" },
536	{ "PAPI_tot_ins", "Instr_cnt" },
537	{ "PAPI_tot_iis",  "Instr_cnt" },
538	{ "PAPI_fml_ins",  "FM_pipe_completion" },
539	{ "PAPI_l1_icm",   "IC_L2_req" },
540	{ "PAPI_l1_ldm",   "DC_rd_miss" },
541	{ "PAPI_l1_dcw",   "DC_wr" },
542	{ "PAPI_l2_tcm",   "L2_miss" },
543	{ "PAPI_l3_tcm",   "L3_miss" },
544	{ "PAPI_l3_icm",   "L3_IC_miss" },
545	{ "PAPI_tlb_im",   "ITLB_miss" },
546	{ "PAPI_tlb_dm",   "DTLB_miss" },
547	{ "PAPI_br_tkn",   "IU_stat_br_count_taken" },
548	CPC_GEN_END
549};
550
551static const us_generic_event_t *US12_generic_names[2] = {
552	US12_generic_names0,
553	US12_generic_names1
554};
555
556static const us_generic_event_t *US3_generic_names[2] = {
557	US3_generic_names0,
558	US3_generic_names1
559};
560
561static const us_generic_event_t *US4_PLUS_generic_names[2] = {
562	US4_PLUS_generic_names0,
563	US4_PLUS_generic_names1
564};
565
566static const struct nametable **events;
567static const us_generic_event_t **generic_events;
568static const char *us_impl_name;
569static const char *us_cpuref;
570static char *pic_events[2];
571static uint16_t pcr_pic_mask;
572
573#define	CPU_REF_URL " Documentation for Sun processors can be found at: " \
574			"http://www.sun.com/processors/manuals"
575
576static const char *us_2_ref = "See the \"UltraSPARC I/II User\'s Manual\" "
577			"(Part No. 802-7220-02) "
578			"for descriptions of these events." CPU_REF_URL;
579
580static const char *us_3cu_ref = "See the \"UltraSPARC III Cu User's Manual\" "
581			"for descriptions of these events." CPU_REF_URL;
582
583static const char *us4_plus_ref = "See the \"UltraSPARC IV+ User's Manual\" "
584			"for descriptions of these events." CPU_REF_URL;
585
586static const char *us_3i_ref = "See the \"UltraSPARC IIIi User's Manual\"  "
587			"for descriptions of these events." CPU_REF_URL;
588
589static int
590us_pcbe_init(void)
591{
592	const struct nametable		*n;
593	const us_generic_event_t	*gevp;
594	int				i;
595	size_t				size;
596
597	/*
598	 * Discover type of CPU
599	 *
600	 * Point nametable to that CPU's table
601	 */
602	switch (ULTRA_VER_IMPL(ultra_getver())) {
603	case SPITFIRE_IMPL:
604	case BLACKBIRD_IMPL:
605	case SABRE_IMPL:
606	case HUMMBRD_IMPL:
607		events = US12_names;
608		generic_events = US12_generic_names;
609		us_impl_name = "UltraSPARC I&II";
610		us_cpuref = us_2_ref;
611		pcr_pic_mask = CPC_ULTRA2_PCR_PIC_MASK;
612		us_pcbe_ops.pcbe_caps &= ~CPC_CAP_OVERFLOW_INTERRUPT;
613		break;
614	case CHEETAH_IMPL:
615		events = US3_names;
616		generic_events = US3_generic_names;
617		us_impl_name = "UltraSPARC III";
618		us_cpuref = us_3cu_ref;
619		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
620		break;
621	case CHEETAH_PLUS_IMPL:
622	case JAGUAR_IMPL:
623		events = US3_PLUS_names;
624		generic_events = US3_generic_names;
625		us_impl_name = "UltraSPARC III+ & IV";
626		us_cpuref = us_3cu_ref;
627		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
628		break;
629	case PANTHER_IMPL:
630		events = US4_PLUS_names;
631		generic_events = US4_PLUS_generic_names;
632		us_impl_name = "UltraSPARC IV+";
633		us_cpuref = us4_plus_ref;
634		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
635		break;
636	case JALAPENO_IMPL:
637	case SERRANO_IMPL:
638		events = US3_I_names;
639		generic_events = US3_generic_names;
640		us_impl_name = "UltraSPARC IIIi & IIIi+";
641		us_cpuref = us_3i_ref;
642		pcr_pic_mask = CPC_ULTRA3_PCR_PIC_MASK;
643		break;
644	default:
645		return (-1);
646	}
647
648	/*
649	 * Initialize the list of events for each PIC.
650	 * Do two passes: one to compute the size necessary and another
651	 * to copy the strings. Need room for event, comma, and NULL terminator.
652	 */
653	for (i = 0; i < 2; i++) {
654		size = 0;
655		for (n = events[i]; n->bits != NT_END; n++)
656			size += strlen(n->name) + 1;
657		for (gevp = generic_events[i]; gevp->name != NULL; gevp++)
658			size += strlen(gevp->name) + 1;
659		pic_events[i] = kmem_alloc(size + 1, KM_SLEEP);
660		*pic_events[i] = '\0';
661		for (n = events[i]; n->bits != NT_END; n++) {
662			(void) strcat(pic_events[i], n->name);
663			(void) strcat(pic_events[i], ",");
664		}
665		for (gevp = generic_events[i]; gevp->name != NULL; gevp++) {
666			(void) strcat(pic_events[i], gevp->name);
667			(void) strcat(pic_events[i], ",");
668		}
669
670		/*
671		 * Remove trailing comma.
672		 */
673		pic_events[i][size - 1] = '\0';
674	}
675
676	return (0);
677}
678
679static uint_t
680us_pcbe_ncounters(void)
681{
682	return (2);
683}
684
685static const char *
686us_pcbe_impl_name(void)
687{
688	return (us_impl_name);
689}
690
691static const char *
692us_pcbe_cpuref(void)
693{
694	return (us_cpuref);
695}
696
697static char *
698us_pcbe_list_events(uint_t picnum)
699{
700	ASSERT(picnum >= 0 && picnum < cpc_ncounters);
701
702	return (pic_events[picnum]);
703}
704
705static char *
706us_pcbe_list_attrs(void)
707{
708	return ("");
709}
710
711static const us_generic_event_t *
712find_generic_event(int regno, char *name)
713{
714	const us_generic_event_t *gevp;
715
716	for (gevp = generic_events[regno]; gevp->name != NULL; gevp++)
717		if (strcmp(name, gevp->name) == 0)
718			return (gevp);
719
720	return (NULL);
721}
722
723static const struct nametable *
724find_event(int regno, char *name)
725{
726	const struct nametable *n;
727
728	n = events[regno];
729
730	for (; n->bits != NT_END; n++)
731		if (strcmp(name, n->name) == 0)
732			return (n);
733
734	return (NULL);
735}
736
737static uint64_t
738us_pcbe_event_coverage(char *event)
739{
740	uint64_t bitmap = 0;
741
742	if ((find_event(0, event) != NULL) ||
743	    (find_generic_event(0, event) != NULL))
744		bitmap = 0x1;
745	if ((find_event(1, event) != NULL) ||
746	    (find_generic_event(1, event) != NULL))
747		bitmap |= 0x2;
748
749	return (bitmap);
750}
751
752/*
753 * These processors cannot tell which counter overflowed. The PCBE interface
754 * requires such processors to act as if _all_ counters had overflowed.
755 */
756static uint64_t
757us_pcbe_overflow_bitmap(void)
758{
759	return (0x3);
760}
761
762/*ARGSUSED*/
763static int
764us_pcbe_configure(uint_t picnum, char *event, uint64_t preset, uint32_t flags,
765    uint_t nattrs, kcpc_attr_t *attrs, void **data, void *token)
766{
767	us_pcbe_config_t		*conf;
768	const struct nametable		*n;
769	const us_generic_event_t	*gevp;
770	us_pcbe_config_t		*other_config;
771
772	/*
773	 * If we've been handed an existing configuration, we need only preset
774	 * the counter value.
775	 */
776	if (*data != NULL) {
777		conf = *data;
778		conf->us_pic = (uint32_t)preset;
779		return (0);
780	}
781
782	if (picnum < 0 || picnum > 1)
783		return (CPC_INVALID_PICNUM);
784
785	if (nattrs != 0)
786		return (CPC_INVALID_ATTRIBUTE);
787
788	/*
789	 * Find other requests that will be programmed with this one, and ensure
790	 * the flags don't conflict.
791	 */
792	if (((other_config = kcpc_next_config(token, NULL, NULL)) != NULL) &&
793	    (other_config->us_flags != flags))
794		return (CPC_CONFLICTING_REQS);
795
796	if ((n = find_event(picnum, event)) == NULL) {
797		if ((gevp = find_generic_event(picnum, event)) != NULL) {
798			n = find_event(picnum, gevp->event);
799			ASSERT(n != NULL);
800		} else {
801			return (CPC_INVALID_EVENT);
802		}
803	}
804
805	conf = kmem_alloc(sizeof (us_pcbe_config_t), KM_SLEEP);
806
807	conf->us_picno = picnum;
808	conf->us_bits = (uint32_t)n->bits;
809	conf->us_flags = flags;
810	conf->us_pic = (uint32_t)preset;
811
812	*data = conf;
813	return (0);
814}
815
816static void
817us_pcbe_program(void *token)
818{
819	us_pcbe_config_t	*pic0;
820	us_pcbe_config_t	*pic1;
821	us_pcbe_config_t	*tmp;
822	us_pcbe_config_t	empty = { 1, 0x1c, 0, 0 }; /* SW_count_1 */
823	uint64_t		pcr;
824	uint64_t		curpic;
825
826	if ((pic0 = (us_pcbe_config_t *)kcpc_next_config(token, NULL, NULL)) ==
827	    NULL)
828		panic("us_pcbe: token %p has no configs", token);
829
830	if ((pic1 = kcpc_next_config(token, pic0, NULL)) == NULL) {
831		pic1 = &empty;
832		empty.us_flags = pic0->us_flags;
833	}
834
835	if (pic0->us_picno != 0) {
836		/*
837		 * pic0 is counter 1, so if we need the empty config it should
838		 * be counter 0.
839		 */
840		empty.us_picno = 0;
841		empty.us_bits = 0x14; /* SW_count_0 - won't overflow */
842		tmp = pic0;
843		pic0 = pic1;
844		pic1 = tmp;
845	}
846
847	if (pic0->us_picno != 0 || pic1->us_picno != 1)
848		panic("us_pcbe: bad config on token %p\n", token);
849
850	/*
851	 * UltraSPARC does not allow pic0 to be configured differently
852	 * from pic1. If the flags on these two configurations are
853	 * different, they are incompatible. This condition should be
854	 * caught at configure time.
855	 */
856	ASSERT(pic0->us_flags == pic1->us_flags);
857
858	ultra_setpcr(allstopped);
859	ultra_setpic(((uint64_t)pic1->us_pic << 32) | (uint64_t)pic0->us_pic);
860
861	pcr = (pic0->us_bits & pcr_pic_mask) <<
862	    CPC_ULTRA_PCR_PIC0_SHIFT;
863	pcr |= (pic1->us_bits & pcr_pic_mask) <<
864	    CPC_ULTRA_PCR_PIC1_SHIFT;
865
866	if (pic0->us_flags & CPC_COUNT_USER)
867		pcr |= (1ull << CPC_ULTRA_PCR_USR);
868	if (pic0->us_flags & CPC_COUNT_SYSTEM)
869		pcr |= (1ull << CPC_ULTRA_PCR_SYS);
870
871	DTRACE_PROBE1(ultra__pcr, uint64_t, pcr);
872
873	ultra_setpcr(pcr);
874
875	/*
876	 * On UltraSPARC, only read-to-read counts are accurate. We cannot
877	 * expect the value we wrote into the PIC, above, to be there after
878	 * starting the counter. We must sample the counter value now and use
879	 * that as the baseline for future samples.
880	 */
881	curpic = ultra_getpic();
882	pic0->us_pic = (uint32_t)(curpic & PIC0_MASK);
883	pic1->us_pic = (uint32_t)(curpic >> 32);
884}
885
886static void
887us_pcbe_allstop(void)
888{
889	ultra_setpcr(allstopped);
890}
891
892
893static void
894us_pcbe_sample(void *token)
895{
896	uint64_t		curpic;
897	int64_t			diff;
898	uint64_t		*pic0_data;
899	uint64_t		*pic1_data;
900	uint64_t		*dtmp;
901	uint64_t		tmp;
902	us_pcbe_config_t	*pic0;
903	us_pcbe_config_t	*pic1;
904	us_pcbe_config_t	empty = { 1, 0, 0, 0 };
905	us_pcbe_config_t	*ctmp;
906
907	curpic = ultra_getpic();
908
909	if ((pic0 = kcpc_next_config(token, NULL, &pic0_data)) == NULL)
910		panic("us_pcbe: token %p has no configs", token);
911
912	if ((pic1 = kcpc_next_config(token, pic0, &pic1_data)) == NULL) {
913		pic1 = &empty;
914		pic1_data = &tmp;
915	}
916
917	if (pic0->us_picno != 0) {
918		empty.us_picno = 0;
919		ctmp = pic0;
920		pic0 = pic1;
921		pic1 = ctmp;
922		dtmp = pic0_data;
923		pic0_data = pic1_data;
924		pic1_data = dtmp;
925	}
926
927	if (pic0->us_picno != 0 || pic1->us_picno != 1)
928		panic("us_pcbe: bad config on token %p\n", token);
929
930	diff = (curpic & PIC0_MASK) - (uint64_t)pic0->us_pic;
931	if (diff < 0)
932		diff += (1ll << 32);
933	*pic0_data += diff;
934
935	diff = (curpic >> 32) - (uint64_t)pic1->us_pic;
936	if (diff < 0)
937		diff += (1ll << 32);
938	*pic1_data += diff;
939
940	pic0->us_pic = (uint32_t)(curpic & PIC0_MASK);
941	pic1->us_pic = (uint32_t)(curpic >> 32);
942}
943
944static void
945us_pcbe_free(void *config)
946{
947	kmem_free(config, sizeof (us_pcbe_config_t));
948}
949
950
951static struct modlpcbe modlpcbe = {
952	&mod_pcbeops,
953	"UltraSPARC Performance Counters",
954	&us_pcbe_ops
955};
956
957static struct modlinkage modl = {
958	MODREV_1,
959	&modlpcbe,
960};
961
962int
963_init(void)
964{
965	if (us_pcbe_init() != 0)
966		return (ENOTSUP);
967	return (mod_install(&modl));
968}
969
970int
971_fini(void)
972{
973	return (mod_remove(&modl));
974}
975
976int
977_info(struct modinfo *mi)
978{
979	return (mod_info(&modl, mi));
980}
981