blob: 3d9ab5be23d8e2a71ede19b07fd8d276ba8daf61 [file] [log] [blame]
David S. Miller3eb80572009-01-21 21:30:23 -08001/* pcr.c: Generic sparc64 performance counter infrastructure.
2 *
3 * Copyright (C) 2009 David S. Miller (davem@davemloft.net)
4 */
5#include <linux/kernel.h>
Paul Gortmaker066bcac2011-07-22 13:18:16 -04006#include <linux/export.h>
David S. Miller3eb80572009-01-21 21:30:23 -08007#include <linux/init.h>
8#include <linux/irq.h>
9
Peter Zijlstrae360adb2010-10-14 14:01:34 +080010#include <linux/irq_work.h>
David S. Miller9960e9e2010-04-07 04:41:33 -070011#include <linux/ftrace.h>
David S. Miller5686f9c2009-09-10 05:59:24 -070012
David S. Miller3eb80572009-01-21 21:30:23 -080013#include <asm/pil.h>
14#include <asm/pcr.h>
David S. Millere5553a62009-01-29 21:22:47 -080015#include <asm/nmi.h>
Paul Gortmakerc2068da2011-08-01 13:42:48 -040016#include <asm/spitfire.h>
David Howellsd550bbd2012-03-28 18:30:03 +010017#include <asm/perfctr.h>
David S. Miller3eb80572009-01-21 21:30:23 -080018
19/* This code is shared between various users of the performance
20 * counters. Users will be oprofile, pseudo-NMI watchdog, and the
Ingo Molnarcdd6c482009-09-21 12:02:48 +020021 * perf_event support layer.
David S. Miller3eb80572009-01-21 21:30:23 -080022 */
23
David S. Millere5553a62009-01-29 21:22:47 -080024#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
25#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
26 PCR_N2_TOE_OV1 | \
27 (2 << PCR_N2_SL1_SHIFT) | \
28 (0xff << PCR_N2_MASK1_SHIFT))
29
30u64 pcr_enable;
31unsigned int picl_shift;
32
David S. Miller3eb80572009-01-21 21:30:23 -080033/* Performance counter interrupts run unmasked at PIL level 15.
34 * Therefore we can't do things like wakeups and other work
35 * that expects IRQ disabling to be adhered to in locking etc.
36 *
37 * Therefore in such situations we defer the work by signalling
38 * a lower level cpu IRQ.
39 */
David S. Miller9960e9e2010-04-07 04:41:33 -070040void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
David S. Miller3eb80572009-01-21 21:30:23 -080041{
David S. Miller5686f9c2009-09-10 05:59:24 -070042 struct pt_regs *old_regs;
43
David S. Miller3eb80572009-01-21 21:30:23 -080044 clear_softint(1 << PIL_DEFERRED_PCR_WORK);
David S. Miller5686f9c2009-09-10 05:59:24 -070045
46 old_regs = set_irq_regs(regs);
47 irq_enter();
Peter Zijlstrae360adb2010-10-14 14:01:34 +080048#ifdef CONFIG_IRQ_WORK
49 irq_work_run();
David S. Miller5686f9c2009-09-10 05:59:24 -070050#endif
51 irq_exit();
52 set_irq_regs(old_regs);
David S. Miller3eb80572009-01-21 21:30:23 -080053}
54
Peter Zijlstrae360adb2010-10-14 14:01:34 +080055void arch_irq_work_raise(void)
David S. Miller3eb80572009-01-21 21:30:23 -080056{
57 set_softint(1 << PIL_DEFERRED_PCR_WORK);
58}
59
60const struct pcr_ops *pcr_ops;
61EXPORT_SYMBOL_GPL(pcr_ops);
62
David S. Miller0bab20b2012-08-16 21:16:22 -070063static u64 direct_pcr_read(unsigned long reg_num)
David S. Miller3eb80572009-01-21 21:30:23 -080064{
65 u64 val;
66
David S. Miller0bab20b2012-08-16 21:16:22 -070067 WARN_ON_ONCE(reg_num != 0);
David S. Miller3eb80572009-01-21 21:30:23 -080068 read_pcr(val);
69 return val;
70}
71
David S. Miller0bab20b2012-08-16 21:16:22 -070072static void direct_pcr_write(unsigned long reg_num, u64 val)
David S. Miller3eb80572009-01-21 21:30:23 -080073{
David S. Miller0bab20b2012-08-16 21:16:22 -070074 WARN_ON_ONCE(reg_num != 0);
David S. Miller3eb80572009-01-21 21:30:23 -080075 write_pcr(val);
76}
77
78static const struct pcr_ops direct_pcr_ops = {
79 .read = direct_pcr_read,
80 .write = direct_pcr_write,
81};
82
David S. Miller0bab20b2012-08-16 21:16:22 -070083static void n2_pcr_write(unsigned long reg_num, u64 val)
David S. Miller3eb80572009-01-21 21:30:23 -080084{
85 unsigned long ret;
86
David S. Miller0bab20b2012-08-16 21:16:22 -070087 WARN_ON_ONCE(reg_num != 0);
David S. Miller314ff522011-07-27 20:46:25 -070088 if (val & PCR_N2_HTRACE) {
89 ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
90 if (ret != HV_EOK)
91 write_pcr(val);
92 } else
David S. Miller3eb80572009-01-21 21:30:23 -080093 write_pcr(val);
94}
95
96static const struct pcr_ops n2_pcr_ops = {
97 .read = direct_pcr_read,
98 .write = n2_pcr_write,
99};
100
101static unsigned long perf_hsvc_group;
102static unsigned long perf_hsvc_major;
103static unsigned long perf_hsvc_minor;
104
105static int __init register_perf_hsvc(void)
106{
107 if (tlb_type == hypervisor) {
108 switch (sun4v_chip_type) {
109 case SUN4V_CHIP_NIAGARA1:
110 perf_hsvc_group = HV_GRP_NIAG_PERF;
111 break;
112
113 case SUN4V_CHIP_NIAGARA2:
114 perf_hsvc_group = HV_GRP_N2_CPU;
115 break;
116
David S. Miller4ba991d2011-07-27 21:06:16 -0700117 case SUN4V_CHIP_NIAGARA3:
118 perf_hsvc_group = HV_GRP_KT_CPU;
119 break;
120
David S. Miller3eb80572009-01-21 21:30:23 -0800121 default:
122 return -ENODEV;
123 }
124
125
126 perf_hsvc_major = 1;
127 perf_hsvc_minor = 0;
128 if (sun4v_hvapi_register(perf_hsvc_group,
129 perf_hsvc_major,
130 &perf_hsvc_minor)) {
131 printk("perfmon: Could not register hvapi.\n");
132 return -ENODEV;
133 }
134 }
135 return 0;
136}
137
138static void __init unregister_perf_hsvc(void)
139{
140 if (tlb_type != hypervisor)
141 return;
142 sun4v_hvapi_unregister(perf_hsvc_group);
143}
144
145int __init pcr_arch_init(void)
146{
147 int err = register_perf_hsvc();
148
149 if (err)
150 return err;
151
152 switch (tlb_type) {
153 case hypervisor:
154 pcr_ops = &n2_pcr_ops;
David S. Millere5553a62009-01-29 21:22:47 -0800155 pcr_enable = PCR_N2_ENABLE;
156 picl_shift = 2;
David S. Miller3eb80572009-01-21 21:30:23 -0800157 break;
158
David S. Miller3eb80572009-01-21 21:30:23 -0800159 case cheetah:
160 case cheetah_plus:
161 pcr_ops = &direct_pcr_ops;
David S. Millere5553a62009-01-29 21:22:47 -0800162 pcr_enable = PCR_SUN4U_ENABLE;
David S. Miller3eb80572009-01-21 21:30:23 -0800163 break;
164
David S. Miller1c2f61d2009-02-05 23:59:04 -0800165 case spitfire:
166 /* UltraSPARC-I/II and derivatives lack a profile
167 * counter overflow interrupt so we can't make use of
168 * their hardware currently.
169 */
170 /* fallthrough */
David S. Miller3eb80572009-01-21 21:30:23 -0800171 default:
172 err = -ENODEV;
173 goto out_unregister;
174 }
175
David S. Millere5553a62009-01-29 21:22:47 -0800176 return nmi_init();
David S. Miller3eb80572009-01-21 21:30:23 -0800177
178out_unregister:
179 unregister_perf_hsvc();
180 return err;
181}