blob: 708406d72bb1361844e73bd3b93ef01fe6fe0650 [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>
6#include <linux/module.h>
7#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 S. Miller3eb80572009-01-21 21:30:23 -080017
18/* This code is shared between various users of the performance
19 * counters. Users will be oprofile, pseudo-NMI watchdog, and the
Ingo Molnarcdd6c482009-09-21 12:02:48 +020020 * perf_event support layer.
David S. Miller3eb80572009-01-21 21:30:23 -080021 */
22
David S. Millere5553a62009-01-29 21:22:47 -080023#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
24#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
25 PCR_N2_TOE_OV1 | \
26 (2 << PCR_N2_SL1_SHIFT) | \
27 (0xff << PCR_N2_MASK1_SHIFT))
28
29u64 pcr_enable;
30unsigned int picl_shift;
31
David S. Miller3eb80572009-01-21 21:30:23 -080032/* Performance counter interrupts run unmasked at PIL level 15.
33 * Therefore we can't do things like wakeups and other work
34 * that expects IRQ disabling to be adhered to in locking etc.
35 *
36 * Therefore in such situations we defer the work by signalling
37 * a lower level cpu IRQ.
38 */
David S. Miller9960e9e2010-04-07 04:41:33 -070039void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs)
David S. Miller3eb80572009-01-21 21:30:23 -080040{
David S. Miller5686f9c2009-09-10 05:59:24 -070041 struct pt_regs *old_regs;
42
David S. Miller3eb80572009-01-21 21:30:23 -080043 clear_softint(1 << PIL_DEFERRED_PCR_WORK);
David S. Miller5686f9c2009-09-10 05:59:24 -070044
45 old_regs = set_irq_regs(regs);
46 irq_enter();
Peter Zijlstrae360adb2010-10-14 14:01:34 +080047#ifdef CONFIG_IRQ_WORK
48 irq_work_run();
David S. Miller5686f9c2009-09-10 05:59:24 -070049#endif
50 irq_exit();
51 set_irq_regs(old_regs);
David S. Miller3eb80572009-01-21 21:30:23 -080052}
53
Peter Zijlstrae360adb2010-10-14 14:01:34 +080054void arch_irq_work_raise(void)
David S. Miller3eb80572009-01-21 21:30:23 -080055{
56 set_softint(1 << PIL_DEFERRED_PCR_WORK);
57}
58
59const struct pcr_ops *pcr_ops;
60EXPORT_SYMBOL_GPL(pcr_ops);
61
62static u64 direct_pcr_read(void)
63{
64 u64 val;
65
66 read_pcr(val);
67 return val;
68}
69
70static void direct_pcr_write(u64 val)
71{
72 write_pcr(val);
73}
74
75static const struct pcr_ops direct_pcr_ops = {
76 .read = direct_pcr_read,
77 .write = direct_pcr_write,
78};
79
80static void n2_pcr_write(u64 val)
81{
82 unsigned long ret;
83
David S. Miller314ff522011-07-27 20:46:25 -070084 if (val & PCR_N2_HTRACE) {
85 ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
86 if (ret != HV_EOK)
87 write_pcr(val);
88 } else
David S. Miller3eb80572009-01-21 21:30:23 -080089 write_pcr(val);
90}
91
92static const struct pcr_ops n2_pcr_ops = {
93 .read = direct_pcr_read,
94 .write = n2_pcr_write,
95};
96
97static unsigned long perf_hsvc_group;
98static unsigned long perf_hsvc_major;
99static unsigned long perf_hsvc_minor;
100
101static int __init register_perf_hsvc(void)
102{
103 if (tlb_type == hypervisor) {
104 switch (sun4v_chip_type) {
105 case SUN4V_CHIP_NIAGARA1:
106 perf_hsvc_group = HV_GRP_NIAG_PERF;
107 break;
108
109 case SUN4V_CHIP_NIAGARA2:
110 perf_hsvc_group = HV_GRP_N2_CPU;
111 break;
112
David S. Miller4ba991d2011-07-27 21:06:16 -0700113 case SUN4V_CHIP_NIAGARA3:
114 perf_hsvc_group = HV_GRP_KT_CPU;
115 break;
116
David S. Miller3eb80572009-01-21 21:30:23 -0800117 default:
118 return -ENODEV;
119 }
120
121
122 perf_hsvc_major = 1;
123 perf_hsvc_minor = 0;
124 if (sun4v_hvapi_register(perf_hsvc_group,
125 perf_hsvc_major,
126 &perf_hsvc_minor)) {
127 printk("perfmon: Could not register hvapi.\n");
128 return -ENODEV;
129 }
130 }
131 return 0;
132}
133
134static void __init unregister_perf_hsvc(void)
135{
136 if (tlb_type != hypervisor)
137 return;
138 sun4v_hvapi_unregister(perf_hsvc_group);
139}
140
141int __init pcr_arch_init(void)
142{
143 int err = register_perf_hsvc();
144
145 if (err)
146 return err;
147
148 switch (tlb_type) {
149 case hypervisor:
150 pcr_ops = &n2_pcr_ops;
David S. Millere5553a62009-01-29 21:22:47 -0800151 pcr_enable = PCR_N2_ENABLE;
152 picl_shift = 2;
David S. Miller3eb80572009-01-21 21:30:23 -0800153 break;
154
David S. Miller3eb80572009-01-21 21:30:23 -0800155 case cheetah:
156 case cheetah_plus:
157 pcr_ops = &direct_pcr_ops;
David S. Millere5553a62009-01-29 21:22:47 -0800158 pcr_enable = PCR_SUN4U_ENABLE;
David S. Miller3eb80572009-01-21 21:30:23 -0800159 break;
160
David S. Miller1c2f61d2009-02-05 23:59:04 -0800161 case spitfire:
162 /* UltraSPARC-I/II and derivatives lack a profile
163 * counter overflow interrupt so we can't make use of
164 * their hardware currently.
165 */
166 /* fallthrough */
David S. Miller3eb80572009-01-21 21:30:23 -0800167 default:
168 err = -ENODEV;
169 goto out_unregister;
170 }
171
David S. Millere5553a62009-01-29 21:22:47 -0800172 return nmi_init();
David S. Miller3eb80572009-01-21 21:30:23 -0800173
174out_unregister:
175 unregister_perf_hsvc();
176 return err;
177}