aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-11-26 01:29:24 -0500
committerDavid S. Miller <davem@davemloft.net>2008-12-04 12:17:05 -0500
commit422e23ea0865177b61527874b1b80023e4215d67 (patch)
treecd65ad354083699b60ebcec2b27e147a0081a123 /arch/sparc
parent456cad8e4e1754672e6df1e716cff1482ea124ce (diff)
sparc64: Use NMI oprofile profiling on cheetah and derivative cpus.
We use clock cycle counter, adjusted to HZ. This can be extended to sun4v based processors as well, as they also have a proper overflow interrupt facility for the performance counters. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/oprofile/init.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
index 17bb6035069b..e979dcd77726 100644
--- a/arch/sparc/oprofile/init.c
+++ b/arch/sparc/oprofile/init.c
@@ -12,9 +12,117 @@
12#include <linux/errno.h> 12#include <linux/errno.h>
13#include <linux/init.h> 13#include <linux/init.h>
14 14
15#ifdef CONFIG_SPARC64
16#include <asm/spitfire.h>
17#include <asm/cpudata.h>
18#include <asm/irq.h>
19
20static int nmi_enabled;
21
22static u64 picl_value(void)
23{
24 u32 delta = local_cpu_data().clock_tick / HZ;
25
26 return (0 - delta) & 0xffffffff;
27}
28
29#define PCR_PIC_PRIV 0x1 /* PIC access is privileged */
30#define PCR_STRACE 0x2 /* Trace supervisor events */
31#define PCR_UTRACE 0x4 /* Trace user events */
32
33static void nmi_handler(struct pt_regs *regs)
34{
35 write_pcr(PCR_PIC_PRIV);
36
37 if (nmi_enabled) {
38 oprofile_add_sample(regs, 0);
39
40 write_pic(picl_value());
41 write_pcr(PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE);
42 }
43}
44
45/* We count "clock cycle" events in the lower 32-bit PIC.
46 * Then configure it such that it overflows every HZ, and thus
47 * generates a level 15 interrupt at that frequency.
48 */
49static void cpu_nmi_start(void *_unused)
50{
51 write_pcr(PCR_PIC_PRIV);
52 write_pic(picl_value());
53
54 /* Bit 0: PIC access is privileged
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}
62
63static void cpu_nmi_stop(void *_unused)
64{
65 write_pcr(PCR_PIC_PRIV);
66}
67
68static int nmi_start(void)
69{
70 int err = register_perfctr_intr(nmi_handler);
71
72 if (!err) {
73 nmi_enabled = 1;
74 wmb();
75 err = on_each_cpu(cpu_nmi_start, NULL, 1);
76 if (err) {
77 nmi_enabled = 0;
78 wmb();
79 on_each_cpu(cpu_nmi_stop, NULL, 1);
80 release_perfctr_intr(nmi_handler);
81 }
82 }
83
84 return err;
85}
86
87static void nmi_stop(void)
88{
89 nmi_enabled = 0;
90 wmb();
91
92 on_each_cpu(cpu_nmi_stop, NULL, 1);
93 release_perfctr_intr(nmi_handler);
94 synchronize_sched();
95}
96
97static int oprofile_nmi_init(struct oprofile_operations *ops)
98{
99 if (tlb_type != cheetah && tlb_type != cheetah_plus)
100 return -ENODEV;
101
102 ops->create_files = NULL;
103 ops->setup = NULL;
104 ops->shutdown = NULL;
105 ops->start = nmi_start;
106 ops->stop = nmi_stop;
107 ops->cpu_type = "timer";
108
109 printk(KERN_INFO "oprofile: Using perfctr based NMI timer interrupt.\n");
110
111 return 0;
112}
113#endif
114
15int __init oprofile_arch_init(struct oprofile_operations *ops) 115int __init oprofile_arch_init(struct oprofile_operations *ops)
16{ 116{
17 return -ENODEV; 117 int ret = -ENODEV;
118
119#ifdef CONFIG_SPARC64
120 ret = oprofile_nmi_init(ops);
121 if (!ret)
122 return ret;
123#endif
124
125 return ret;
18} 126}
19 127
20 128