aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/oprofile
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-11-28 05:27:42 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:10 -0500
commit63ef34827c1f5ac838e869cc3ecc2d9cfebae152 (patch)
tree6d78a639e127bafb0293ed7a3918c90d0ebfc5fa /arch/sparc/oprofile
parent3178a07c33747305b7f7140bd55b0f77e7f239eb (diff)
sparc64: Provide oprofile pseudo-NMI on Niagara.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/oprofile')
-rw-r--r--arch/sparc/oprofile/init.c151
1 files changed, 135 insertions, 16 deletions
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
index e979dcd77726..d6e170c074fc 100644
--- a/arch/sparc/oprofile/init.c
+++ b/arch/sparc/oprofile/init.c
@@ -13,32 +13,97 @@
13#include <linux/init.h> 13#include <linux/init.h>
14 14
15#ifdef CONFIG_SPARC64 15#ifdef CONFIG_SPARC64
16#include <asm/hypervisor.h>
16#include <asm/spitfire.h> 17#include <asm/spitfire.h>
17#include <asm/cpudata.h> 18#include <asm/cpudata.h>
18#include <asm/irq.h> 19#include <asm/irq.h>
19 20
20static int nmi_enabled; 21static int nmi_enabled;
21 22
23struct pcr_ops {
24 u64 (*read)(void);
25 void (*write)(u64);
26};
27static const struct pcr_ops *pcr_ops;
28
29static u64 direct_pcr_read(void)
30{
31 u64 val;
32
33 read_pcr(val);
34 return val;
35}
36
37static void direct_pcr_write(u64 val)
38{
39 write_pcr(val);
40}
41
42static const struct pcr_ops direct_pcr_ops = {
43 .read = direct_pcr_read,
44 .write = direct_pcr_write,
45};
46
47static void n2_pcr_write(u64 val)
48{
49 unsigned long ret;
50
51 ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
52 if (val != HV_EOK)
53 write_pcr(val);
54}
55
56static const struct pcr_ops n2_pcr_ops = {
57 .read = direct_pcr_read,
58 .write = n2_pcr_write,
59};
60
61/* In order to commonize as much of the implementation as
62 * possible, we use PICH as our counter. Mostly this is
63 * to accomodate Niagara-1 which can only count insn cycles
64 * in PICH.
65 */
22static u64 picl_value(void) 66static u64 picl_value(void)
23{ 67{
24 u32 delta = local_cpu_data().clock_tick / HZ; 68 u32 delta = local_cpu_data().clock_tick / HZ;
25 69
26 return (0 - delta) & 0xffffffff; 70 return ((u64)((0 - delta) & 0xffffffff)) << 32;
27} 71}
28 72
29#define PCR_PIC_PRIV 0x1 /* PIC access is privileged */ 73#define PCR_PIC_PRIV 0x00000001 /* PIC access is privileged */
30#define PCR_STRACE 0x2 /* Trace supervisor events */ 74#define PCR_STRACE 0x00000002 /* Trace supervisor events */
31#define PCR_UTRACE 0x4 /* Trace user events */ 75#define PCR_UTRACE 0x00000004 /* Trace user events */
76#define PCR_N2_HTRACE 0x00000008 /* Trace hypervisor events */
77#define PCR_N2_TOE_OV0 0x00000010 /* Trap if PIC 0 overflows */
78#define PCR_N2_TOE_OV1 0x00000020 /* Trap if PIC 1 overflows */
79#define PCR_N2_MASK0 0x00003fc0
80#define PCR_N2_MASK0_SHIFT 6
81#define PCR_N2_SL0 0x0003c000
82#define PCR_N2_SL0_SHIFT 14
83#define PCR_N2_OV0 0x00040000
84#define PCR_N2_MASK1 0x07f80000
85#define PCR_N2_MASK1_SHIFT 19
86#define PCR_N2_SL1 0x78000000
87#define PCR_N2_SL1_SHIFT 27
88#define PCR_N2_OV1 0x80000000
89
90#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
91#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
92 PCR_N2_TOE_OV1 | \
93 (2 << PCR_N2_SL1_SHIFT) | \
94 (0xff << PCR_N2_MASK1_SHIFT))
95
96static u64 pcr_enable = PCR_SUN4U_ENABLE;
32 97
33static void nmi_handler(struct pt_regs *regs) 98static void nmi_handler(struct pt_regs *regs)
34{ 99{
35 write_pcr(PCR_PIC_PRIV); 100 pcr_ops->write(PCR_PIC_PRIV);
36 101
37 if (nmi_enabled) { 102 if (nmi_enabled) {
38 oprofile_add_sample(regs, 0); 103 oprofile_add_sample(regs, 0);
39 104
40 write_pic(picl_value()); 105 write_pic(picl_value());
41 write_pcr(PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE); 106 pcr_ops->write(pcr_enable);
42 } 107 }
43} 108}
44 109
@@ -48,21 +113,15 @@ static void nmi_handler(struct pt_regs *regs)
48 */ 113 */
49static void cpu_nmi_start(void *_unused) 114static void cpu_nmi_start(void *_unused)
50{ 115{
51 write_pcr(PCR_PIC_PRIV); 116 pcr_ops->write(PCR_PIC_PRIV);
52 write_pic(picl_value()); 117 write_pic(picl_value());
53 118
54 /* Bit 0: PIC access is privileged 119 pcr_ops->write(pcr_enable);
55 * Bit 1: Supervisor Trace
56 * Bit 2: User Trace
57 *
58 * And the event selection code for cpu cycles is zero.
59 */
60 write_pcr(PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE);
61} 120}
62 121
63static void cpu_nmi_stop(void *_unused) 122static void cpu_nmi_stop(void *_unused)
64{ 123{
65 write_pcr(PCR_PIC_PRIV); 124 pcr_ops->write(PCR_PIC_PRIV);
66} 125}
67 126
68static int nmi_start(void) 127static int nmi_start(void)
@@ -94,10 +153,67 @@ static void nmi_stop(void)
94 synchronize_sched(); 153 synchronize_sched();
95} 154}
96 155
156static unsigned long perf_hsvc_group;
157static unsigned long perf_hsvc_major;
158static unsigned long perf_hsvc_minor;
159
160static int __init register_perf_hsvc(void)
161{
162 if (tlb_type == hypervisor) {
163 switch (sun4v_chip_type) {
164 case SUN4V_CHIP_NIAGARA1:
165 perf_hsvc_group = HV_GRP_NIAG_PERF;
166 break;
167
168 case SUN4V_CHIP_NIAGARA2:
169 perf_hsvc_group = HV_GRP_N2_CPU;
170 break;
171
172 default:
173 return -ENODEV;
174 }
175
176
177 perf_hsvc_major = 1;
178 perf_hsvc_minor = 0;
179 if (sun4v_hvapi_register(perf_hsvc_group,
180 perf_hsvc_major,
181 &perf_hsvc_minor)) {
182 printk("perfmon: Could not register N2 hvapi.\n");
183 return -ENODEV;
184 }
185 }
186 return 0;
187}
188
189static void unregister_perf_hsvc(void)
190{
191 if (tlb_type != hypervisor)
192 return;
193 sun4v_hvapi_unregister(perf_hsvc_group);
194}
195
97static int oprofile_nmi_init(struct oprofile_operations *ops) 196static int oprofile_nmi_init(struct oprofile_operations *ops)
98{ 197{
99 if (tlb_type != cheetah && tlb_type != cheetah_plus) 198 int err = register_perf_hsvc();
199
200 if (err)
201 return err;
202
203 switch (tlb_type) {
204 case hypervisor:
205 pcr_ops = &n2_pcr_ops;
206 pcr_enable = PCR_N2_ENABLE;
207 break;
208
209 case cheetah:
210 case cheetah_plus:
211 pcr_ops = &direct_pcr_ops;
212 break;
213
214 default:
100 return -ENODEV; 215 return -ENODEV;
216 }
101 217
102 ops->create_files = NULL; 218 ops->create_files = NULL;
103 ops->setup = NULL; 219 ops->setup = NULL;
@@ -128,4 +244,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
128 244
129void oprofile_arch_exit(void) 245void oprofile_arch_exit(void)
130{ 246{
247#ifdef CONFIG_SPARC64
248 unregister_perf_hsvc();
249#endif
131} 250}