4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This file contains preset event names from the Performance Application
28 * Programming Interface v3.5 which included the following notice:
30 * Copyright (c) 2005,6
31 * Innovative Computing Labs
32 * Computer Science Department,
33 * University of Tennessee,
35 * All Rights Reserved.
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions are met:
41 * * Redistributions of source code must retain the above copyright notice,
42 * this list of conditions and the following disclaimer.
43 * * Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * * Neither the name of the University of Tennessee nor the names of its
47 * contributors may be used to endorse or promote products derived from
48 * this software without specific prior written permission.
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
51 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
54 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
55 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
56 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
57 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
58 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
59 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 * POSSIBILITY OF SUCH DAMAGE.
63 * This open source software license conforms to the BSD License template.
67 * Niagara Performance Counter Backend
70 #include <sys/cpuvar.h>
71 #include <sys/systm.h>
72 #include <sys/cmn_err.h>
73 #include <sys/cpc_impl.h>
74 #include <sys/cpc_pcbe.h>
75 #include <sys/modctl.h>
76 #include <sys/machsystm.h>
78 #include <sys/niagararegs.h>
80 static int ni_pcbe_init(void);
81 static uint_t
ni_pcbe_ncounters(void);
82 static const char *ni_pcbe_impl_name(void);
83 static const char *ni_pcbe_cpuref(void);
84 static char *ni_pcbe_list_events(uint_t picnum
);
85 static char *ni_pcbe_list_attrs(void);
86 static uint64_t ni_pcbe_event_coverage(char *event
);
87 static uint64_t ni_pcbe_overflow_bitmap(void);
88 static int ni_pcbe_configure(uint_t picnum
, char *event
, uint64_t preset
,
89 uint32_t flags
, uint_t nattrs
, kcpc_attr_t
*attrs
, void **data
,
91 static void ni_pcbe_program(void *token
);
92 static void ni_pcbe_allstop(void);
93 static void ni_pcbe_sample(void *token
);
94 static void ni_pcbe_free(void *config
);
96 extern void ultra_setpcr(uint64_t);
97 extern uint64_t ultra_getpcr(void);
98 extern void ultra_setpic(uint64_t);
99 extern uint64_t ultra_getpic(void);
100 extern uint64_t ultra_gettick(void);
102 pcbe_ops_t ni_pcbe_ops
= {
104 CPC_CAP_OVERFLOW_INTERRUPT
| CPC_CAP_OVERFLOW_PRECISE
,
110 ni_pcbe_event_coverage
,
111 ni_pcbe_overflow_bitmap
,
119 typedef struct _ni_pcbe_config
{
120 uint8_t pcbe_picno
; /* 0 for pic0 or 1 for pic1 */
121 uint32_t pcbe_bits
; /* %pcr event code unshifted */
122 uint32_t pcbe_flags
; /* user/system/priv */
123 uint32_t pcbe_pic
; /* unshifted raw %pic value */
131 typedef struct _ni_generic_events
{
134 } ni_generic_event_t
;
136 #define ULTRA_PCR_PRIVPIC (UINT64_C(1) << CPC_PCR_PRIVPIC)
138 #define GEN_EVT_END { NULL, NULL }
140 static const uint64_t allstopped
= ULTRA_PCR_PRIVPIC
;
142 static const struct nametable Niagara_names1
[] = {
147 static const struct nametable Niagara_names0
[] = {
149 {0x1, "FP_instr_cnt"},
155 {0x7, "L2_dmiss_ld"},
159 static const struct nametable
*Niagara_names
[2] = {
164 static const ni_generic_event_t Niagara_generic_names1
[] = {
165 { "PAPI_tot_ins", "Instr_cnt" },
169 static const ni_generic_event_t Niagara_generic_names0
[] = {
170 { "PAPI_l2_icm", "L2_imiss" },
171 { "PAPI_l2_ldm", "L2_dmiss_ld" },
172 { "PAPI_fp_ops", "FP_instr_cnt" },
173 { "PAPI_fp_ins", "FP_instr_cnt" },
174 { "PAPI_l1_icm", "IC_miss" },
175 { "PAPI_l1_dcm", "DC_miss" },
176 { "PAPI_tlb_im", "ITLB_miss" },
177 { "PAPI_tlb_dm", "DTLB_miss" },
181 static const ni_generic_event_t
*Niagara_generic_names
[2] = {
182 Niagara_generic_names0
,
183 Niagara_generic_names1
186 static const struct nametable
**events
;
187 static const ni_generic_event_t
**generic_events
;
188 static const char *ni_impl_name
= "UltraSPARC T1";
189 static char *pic_events
[2];
190 static uint16_t pcr_pic0_mask
;
191 static uint16_t pcr_pic1_mask
;
193 #define CPU_REF_URL " Documentation for Sun processors can be found at: " \
194 "http://www.sun.com/processors/manuals"
196 static const char *niagara_cpuref
= "See the \"UltraSPARC T1 User's Manual\" "
197 "for descriptions of these events." CPU_REF_URL
;
202 const struct nametable
*n
;
203 const ni_generic_event_t
*gevp
;
207 events
= Niagara_names
;
208 generic_events
= Niagara_generic_names
;
209 pcr_pic0_mask
= CPC_PCR_PIC0_MASK
;
210 pcr_pic1_mask
= CPC_PCR_PIC1_MASK
;
213 * Initialize the list of events for each PIC.
214 * Do two passes: one to compute the size necessary and another
215 * to copy the strings. Need room for event, comma, and NULL terminator.
217 for (i
= 0; i
< 2; i
++) {
219 for (n
= events
[i
]; n
->bits
!= NT_END
; n
++)
220 size
+= strlen(n
->name
) + 1;
221 for (gevp
= generic_events
[i
]; gevp
->name
!= NULL
; gevp
++)
222 size
+= strlen(gevp
->name
) + 1;
223 pic_events
[i
] = kmem_alloc(size
+ 1, KM_SLEEP
);
224 *pic_events
[i
] = '\0';
225 for (n
= events
[i
]; n
->bits
!= NT_END
; n
++) {
226 (void) strcat(pic_events
[i
], n
->name
);
227 (void) strcat(pic_events
[i
], ",");
229 for (gevp
= generic_events
[i
]; gevp
->name
!= NULL
; gevp
++) {
230 (void) strcat(pic_events
[i
], gevp
->name
);
231 (void) strcat(pic_events
[i
], ",");
234 * Remove trailing comma.
236 pic_events
[i
][size
- 1] = '\0';
243 ni_pcbe_ncounters(void)
249 ni_pcbe_impl_name(void)
251 return (ni_impl_name
);
257 return (niagara_cpuref
);
261 ni_pcbe_list_events(uint_t picnum
)
263 ASSERT(picnum
>= 0 && picnum
< cpc_ncounters
);
265 return (pic_events
[picnum
]);
269 ni_pcbe_list_attrs(void)
274 static const ni_generic_event_t
*
275 find_generic_event(int regno
, char *name
)
277 const ni_generic_event_t
*gevp
;
279 for (gevp
= generic_events
[regno
]; gevp
->name
!= NULL
; gevp
++) {
280 if (strcmp(gevp
->name
, name
) == 0)
287 static const struct nametable
*
288 find_event(int regno
, char *name
)
290 const struct nametable
*n
;
294 for (; n
->bits
!= NT_END
; n
++)
295 if (strcmp(name
, n
->name
) == 0)
302 ni_pcbe_event_coverage(char *event
)
306 if ((find_event(0, event
) != NULL
) ||
307 (find_generic_event(0, event
) != NULL
))
309 if ((find_event(1, event
) != NULL
) ||
310 (find_generic_event(1, event
) != NULL
))
317 * These processors cannot tell which counter overflowed. The PCBE interface
318 * requires such processors to act as if _all_ counters had overflowed.
321 ni_pcbe_overflow_bitmap(void)
323 uint64_t pcr
, overflow
;
325 pcr
= ultra_getpcr();
326 DTRACE_PROBE1(niagara__getpcr
, uint64_t, pcr
);
327 overflow
= (pcr
& CPC_PCR_OVF_MASK
) >>
331 * Not needed if the CPC framework is responsible to stop counters
332 * and that action ends up clearing overflow flags.
335 ultra_setpcr(pcr
& ~CPC_PCR_OVF_MASK
);
342 ni_pcbe_configure(uint_t picnum
, char *event
, uint64_t preset
, uint32_t flags
,
343 uint_t nattrs
, kcpc_attr_t
*attrs
, void **data
, void *token
)
345 ni_pcbe_config_t
*conf
;
346 const struct nametable
*n
;
347 const ni_generic_event_t
*gevp
;
348 ni_pcbe_config_t
*other_config
;
351 * If we've been handed an existing configuration, we need only preset
356 conf
->pcbe_pic
= (uint32_t)preset
;
359 if (picnum
< 0 || picnum
> 1)
360 return (CPC_INVALID_PICNUM
);
363 return (CPC_INVALID_ATTRIBUTE
);
366 * Find other requests that will be programmed with this one, and ensure
367 * the flags don't conflict.
369 if (((other_config
= kcpc_next_config(token
, NULL
, NULL
)) != NULL
) &&
370 (other_config
->pcbe_flags
!= flags
))
371 return (CPC_CONFLICTING_REQS
);
373 if ((n
= find_event(picnum
, event
)) == NULL
) {
374 if ((gevp
= find_generic_event(picnum
, event
)) != NULL
) {
375 n
= find_event(picnum
, gevp
->event
);
378 return (CPC_INVALID_EVENT
);
382 conf
= kmem_alloc(sizeof (ni_pcbe_config_t
), KM_SLEEP
);
384 conf
->pcbe_picno
= picnum
;
385 conf
->pcbe_bits
= (uint32_t)n
->bits
;
386 conf
->pcbe_flags
= flags
;
387 conf
->pcbe_pic
= (uint32_t)preset
;
394 ni_pcbe_program(void *token
)
396 ni_pcbe_config_t
*pic0
;
397 ni_pcbe_config_t
*pic1
;
398 ni_pcbe_config_t
*tmp
;
399 ni_pcbe_config_t empty
= { 1, 0x1c, 0, 0 }; /* SW_count_1 */
403 if ((pic0
= (ni_pcbe_config_t
*)kcpc_next_config(token
, NULL
, NULL
)) ==
405 panic("ni_pcbe: token %p has no configs", token
);
407 if ((pic1
= kcpc_next_config(token
, pic0
, NULL
)) == NULL
) {
409 empty
.pcbe_flags
= pic0
->pcbe_flags
;
412 if (pic0
->pcbe_picno
!= 0) {
414 * pic0 is counter 1, so if we need the empty config it should
417 empty
.pcbe_picno
= 0;
419 /* no selection for counter 0 */
420 empty
.pcbe_bits
= 0x14; /* SW_count_0 - won't overflow */
427 if (pic0
->pcbe_picno
!= 0 || pic1
->pcbe_picno
!= 1)
428 panic("ni_pcbe: bad config on token %p\n", token
);
431 * UltraSPARC does not allow pic0 to be configured differently
432 * from pic1. If the flags on these two configurations are
433 * different, they are incompatible. This condition should be
434 * caught at configure time.
436 ASSERT(pic0
->pcbe_flags
== pic1
->pcbe_flags
);
438 ultra_setpcr(allstopped
);
439 ultra_setpic(((uint64_t)pic1
->pcbe_pic
<< PIC1_SHIFT
) |
440 (uint64_t)pic0
->pcbe_pic
);
442 pcr
= (pic0
->pcbe_bits
& pcr_pic0_mask
) << CPC_PCR_PIC0_SHIFT
;
443 pcr
|= (pic1
->pcbe_bits
& pcr_pic1_mask
) << CPC_PCR_PIC1_SHIFT
;
445 if (pic0
->pcbe_flags
& CPC_COUNT_USER
)
446 pcr
|= (1ull << CPC_PCR_USR
);
447 if (pic0
->pcbe_flags
& CPC_COUNT_SYSTEM
)
448 pcr
|= (1ull << CPC_PCR_SYS
);
450 DTRACE_PROBE1(niagara__setpcr
, uint64_t, pcr
);
454 * On UltraSPARC, only read-to-read counts are accurate. We cannot
455 * expect the value we wrote into the PIC, above, to be there after
456 * starting the counter. We must sample the counter value now and use
457 * that as the baseline for future samples.
459 curpic
= ultra_getpic();
460 pic0
->pcbe_pic
= (uint32_t)(curpic
& PIC0_MASK
);
461 pic1
->pcbe_pic
= (uint32_t)(curpic
>> PIC1_SHIFT
);
462 DTRACE_PROBE1(niagara__newpic
, uint64_t, curpic
);
466 ni_pcbe_allstop(void)
468 ultra_setpcr(allstopped
);
473 ni_pcbe_sample(void *token
)
481 ni_pcbe_config_t
*pic0
;
482 ni_pcbe_config_t
*pic1
;
483 ni_pcbe_config_t empty
= { 1, 0, 0, 0 };
484 ni_pcbe_config_t
*ctmp
;
486 curpic
= ultra_getpic();
487 DTRACE_PROBE1(niagara__getpic
, uint64_t, curpic
);
489 if ((pic0
= kcpc_next_config(token
, NULL
, &pic0_data
)) == NULL
)
490 panic("%s: token %p has no configs", ni_impl_name
, token
);
492 if ((pic1
= kcpc_next_config(token
, pic0
, &pic1_data
)) == NULL
) {
497 if (pic0
->pcbe_picno
!= 0) {
498 empty
.pcbe_picno
= 0;
503 pic0_data
= pic1_data
;
507 if (pic0
->pcbe_picno
!= 0 || pic1
->pcbe_picno
!= 1)
508 panic("%s: bad config on token %p\n", ni_impl_name
, token
);
510 diff
= (curpic
& PIC0_MASK
) - (uint64_t)pic0
->pcbe_pic
;
515 diff
= (curpic
>> 32) - (uint64_t)pic1
->pcbe_pic
;
520 pic0
->pcbe_pic
= (uint32_t)(curpic
& PIC0_MASK
);
521 pic1
->pcbe_pic
= (uint32_t)(curpic
>> PIC1_SHIFT
);
525 ni_pcbe_free(void *config
)
527 kmem_free(config
, sizeof (ni_pcbe_config_t
));
531 static struct modlpcbe modlpcbe
= {
533 "UltraSPARC T1 Performance Counters",
537 static struct modlinkage modl
= {
545 if (ni_pcbe_init() != 0)
547 return (mod_install(&modl
));
553 return (mod_remove(&modl
));
557 _info(struct modinfo
*mi
)
559 return (mod_info(&modl
, mi
));