1 // SPDX-License-Identifier: GPL-2.0-only
2 /* pcr.c: Generic sparc64 performance counter infrastructure.
4 * Copyright (C) 2009 David S. Miller (davem@davemloft.net)
6 #include <linux/kernel.h>
7 #include <linux/export.h>
8 #include <linux/init.h>
11 #include <linux/irq_work.h>
12 #include <linux/ftrace.h>
18 #include <asm/spitfire.h>
20 /* This code is shared between various users of the performance
21 * counters. Users will be oprofile, pseudo-NMI watchdog, and the
22 * perf_event support layer.
25 /* Performance counter interrupts run unmasked at PIL level 15.
26 * Therefore we can't do things like wakeups and other work
27 * that expects IRQ disabling to be adhered to in locking etc.
29 * Therefore in such situations we defer the work by signalling
30 * a lower level cpu IRQ.
32 void __irq_entry
deferred_pcr_work_irq(int irq
, struct pt_regs
*regs
)
34 struct pt_regs
*old_regs
;
36 clear_softint(1 << PIL_DEFERRED_PCR_WORK
);
38 old_regs
= set_irq_regs(regs
);
40 #ifdef CONFIG_IRQ_WORK
44 set_irq_regs(old_regs
);
47 void arch_irq_work_raise(void)
49 set_softint(1 << PIL_DEFERRED_PCR_WORK
);
52 const struct pcr_ops
*pcr_ops
;
53 EXPORT_SYMBOL_GPL(pcr_ops
);
55 static u64
direct_pcr_read(unsigned long reg_num
)
59 WARN_ON_ONCE(reg_num
!= 0);
60 __asm__
__volatile__("rd %%pcr, %0" : "=r" (val
));
64 static void direct_pcr_write(unsigned long reg_num
, u64 val
)
66 WARN_ON_ONCE(reg_num
!= 0);
67 __asm__
__volatile__("wr %0, 0x0, %%pcr" : : "r" (val
));
70 static u64
direct_pic_read(unsigned long reg_num
)
74 WARN_ON_ONCE(reg_num
!= 0);
75 __asm__
__volatile__("rd %%pic, %0" : "=r" (val
));
79 static void direct_pic_write(unsigned long reg_num
, u64 val
)
81 WARN_ON_ONCE(reg_num
!= 0);
83 /* Blackbird errata workaround. See commentary in
84 * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
85 * for more information.
87 __asm__
__volatile__("ba,pt %%xcc, 99f\n\t"
90 "99:wr %0, 0x0, %%pic\n\t"
91 "rd %%pic, %%g0" : : "r" (val
));
94 static u64
direct_picl_value(unsigned int nmi_hz
)
96 u32 delta
= local_cpu_data().clock_tick
/ nmi_hz
;
98 return ((u64
)((0 - delta
) & 0xffffffff)) << 32;
101 static const struct pcr_ops direct_pcr_ops
= {
102 .read_pcr
= direct_pcr_read
,
103 .write_pcr
= direct_pcr_write
,
104 .read_pic
= direct_pic_read
,
105 .write_pic
= direct_pic_write
,
106 .nmi_picl_value
= direct_picl_value
,
107 .pcr_nmi_enable
= (PCR_PIC_PRIV
| PCR_STRACE
| PCR_UTRACE
),
108 .pcr_nmi_disable
= PCR_PIC_PRIV
,
111 static void n2_pcr_write(unsigned long reg_num
, u64 val
)
115 WARN_ON_ONCE(reg_num
!= 0);
116 if (val
& PCR_N2_HTRACE
) {
117 ret
= sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL
, val
);
119 direct_pcr_write(reg_num
, val
);
121 direct_pcr_write(reg_num
, val
);
124 static u64
n2_picl_value(unsigned int nmi_hz
)
126 u32 delta
= local_cpu_data().clock_tick
/ (nmi_hz
<< 2);
128 return ((u64
)((0 - delta
) & 0xffffffff)) << 32;
131 static const struct pcr_ops n2_pcr_ops
= {
132 .read_pcr
= direct_pcr_read
,
133 .write_pcr
= n2_pcr_write
,
134 .read_pic
= direct_pic_read
,
135 .write_pic
= direct_pic_write
,
136 .nmi_picl_value
= n2_picl_value
,
137 .pcr_nmi_enable
= (PCR_PIC_PRIV
| PCR_STRACE
| PCR_UTRACE
|
139 (2 << PCR_N2_SL1_SHIFT
) |
140 (0xff << PCR_N2_MASK1_SHIFT
)),
141 .pcr_nmi_disable
= PCR_PIC_PRIV
,
144 static u64
n4_pcr_read(unsigned long reg_num
)
148 (void) sun4v_vt_get_perfreg(reg_num
, &val
);
153 static void n4_pcr_write(unsigned long reg_num
, u64 val
)
155 (void) sun4v_vt_set_perfreg(reg_num
, val
);
158 static u64
n4_pic_read(unsigned long reg_num
)
162 __asm__
__volatile__("ldxa [%1] %2, %0"
164 : "r" (reg_num
* 0x8UL
), "i" (ASI_PIC
));
169 static void n4_pic_write(unsigned long reg_num
, u64 val
)
171 __asm__
__volatile__("stxa %0, [%1] %2"
173 : "r" (val
), "r" (reg_num
* 0x8UL
), "i" (ASI_PIC
));
176 static u64
n4_picl_value(unsigned int nmi_hz
)
178 u32 delta
= local_cpu_data().clock_tick
/ (nmi_hz
<< 2);
180 return ((u64
)((0 - delta
) & 0xffffffff));
183 static const struct pcr_ops n4_pcr_ops
= {
184 .read_pcr
= n4_pcr_read
,
185 .write_pcr
= n4_pcr_write
,
186 .read_pic
= n4_pic_read
,
187 .write_pic
= n4_pic_write
,
188 .nmi_picl_value
= n4_picl_value
,
189 .pcr_nmi_enable
= (PCR_N4_PICNPT
| PCR_N4_STRACE
|
190 PCR_N4_UTRACE
| PCR_N4_TOE
|
191 (26 << PCR_N4_SL_SHIFT
)),
192 .pcr_nmi_disable
= PCR_N4_PICNPT
,
195 static u64
n5_pcr_read(unsigned long reg_num
)
199 (void) sun4v_t5_get_perfreg(reg_num
, &val
);
204 static void n5_pcr_write(unsigned long reg_num
, u64 val
)
206 (void) sun4v_t5_set_perfreg(reg_num
, val
);
209 static const struct pcr_ops n5_pcr_ops
= {
210 .read_pcr
= n5_pcr_read
,
211 .write_pcr
= n5_pcr_write
,
212 .read_pic
= n4_pic_read
,
213 .write_pic
= n4_pic_write
,
214 .nmi_picl_value
= n4_picl_value
,
215 .pcr_nmi_enable
= (PCR_N4_PICNPT
| PCR_N4_STRACE
|
216 PCR_N4_UTRACE
| PCR_N4_TOE
|
217 (26 << PCR_N4_SL_SHIFT
)),
218 .pcr_nmi_disable
= PCR_N4_PICNPT
,
221 static u64
m7_pcr_read(unsigned long reg_num
)
225 (void) sun4v_m7_get_perfreg(reg_num
, &val
);
230 static void m7_pcr_write(unsigned long reg_num
, u64 val
)
232 (void) sun4v_m7_set_perfreg(reg_num
, val
);
235 static const struct pcr_ops m7_pcr_ops
= {
236 .read_pcr
= m7_pcr_read
,
237 .write_pcr
= m7_pcr_write
,
238 .read_pic
= n4_pic_read
,
239 .write_pic
= n4_pic_write
,
240 .nmi_picl_value
= n4_picl_value
,
241 .pcr_nmi_enable
= (PCR_N4_PICNPT
| PCR_N4_STRACE
|
242 PCR_N4_UTRACE
| PCR_N4_TOE
|
243 (26 << PCR_N4_SL_SHIFT
)),
244 .pcr_nmi_disable
= PCR_N4_PICNPT
,
247 static unsigned long perf_hsvc_group
;
248 static unsigned long perf_hsvc_major
;
249 static unsigned long perf_hsvc_minor
;
251 static int __init
register_perf_hsvc(void)
253 unsigned long hverror
;
255 if (tlb_type
== hypervisor
) {
256 switch (sun4v_chip_type
) {
257 case SUN4V_CHIP_NIAGARA1
:
258 perf_hsvc_group
= HV_GRP_NIAG_PERF
;
261 case SUN4V_CHIP_NIAGARA2
:
262 perf_hsvc_group
= HV_GRP_N2_CPU
;
265 case SUN4V_CHIP_NIAGARA3
:
266 perf_hsvc_group
= HV_GRP_KT_CPU
;
269 case SUN4V_CHIP_NIAGARA4
:
270 perf_hsvc_group
= HV_GRP_VT_CPU
;
273 case SUN4V_CHIP_NIAGARA5
:
274 perf_hsvc_group
= HV_GRP_T5_CPU
;
277 case SUN4V_CHIP_SPARC_M7
:
278 perf_hsvc_group
= HV_GRP_M7_PERF
;
288 hverror
= sun4v_hvapi_register(perf_hsvc_group
,
292 pr_err("perfmon: Could not register hvapi(0x%lx).\n",
300 static void __init
unregister_perf_hsvc(void)
302 if (tlb_type
!= hypervisor
)
304 sun4v_hvapi_unregister(perf_hsvc_group
);
307 static int __init
setup_sun4v_pcr_ops(void)
311 switch (sun4v_chip_type
) {
312 case SUN4V_CHIP_NIAGARA1
:
313 case SUN4V_CHIP_NIAGARA2
:
314 case SUN4V_CHIP_NIAGARA3
:
315 pcr_ops
= &n2_pcr_ops
;
318 case SUN4V_CHIP_NIAGARA4
:
319 pcr_ops
= &n4_pcr_ops
;
322 case SUN4V_CHIP_NIAGARA5
:
323 pcr_ops
= &n5_pcr_ops
;
326 case SUN4V_CHIP_SPARC_M7
:
327 pcr_ops
= &m7_pcr_ops
;
338 int __init
pcr_arch_init(void)
340 int err
= register_perf_hsvc();
347 err
= setup_sun4v_pcr_ops();
354 pcr_ops
= &direct_pcr_ops
;
358 /* UltraSPARC-I/II and derivatives lack a profile
359 * counter overflow interrupt so we can't make use of
360 * their hardware currently.
371 unregister_perf_hsvc();