aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/oprofile/init.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-01-30 00:22:47 -0500
committerDavid S. Miller <davem@davemloft.net>2009-01-30 03:03:53 -0500
commite5553a6d04421eec326a629571d696e8e745a0e4 (patch)
treeb6fe49a18135dbe27a464fb78828b2150c679689 /arch/sparc/oprofile/init.c
parentc3cf5e8cc56d272f828a66610bb78bbb727b2ce1 (diff)
sparc64: Implement NMI watchdog on capable cpus.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/oprofile/init.c')
-rw-r--r--arch/sparc/oprofile/init.c128
1 files changed, 34 insertions, 94 deletions
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
index c8877a5202b0..d172f86439b1 100644
--- a/arch/sparc/oprofile/init.c
+++ b/arch/sparc/oprofile/init.c
@@ -13,117 +13,57 @@
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 <linux/notifier.h>
17#include <asm/spitfire.h> 17#include <linux/rcupdate.h>
18#include <asm/cpudata.h> 18#include <linux/kdebug.h>
19#include <asm/irq.h> 19#include <asm/nmi.h>
20#include <asm/pcr.h>
21 20
22static int nmi_enabled; 21static int profile_timer_exceptions_notify(struct notifier_block *self,
23 22 unsigned long val, void *data)
24/* In order to commonize as much of the implementation as
25 * possible, we use PICH as our counter. Mostly this is
26 * to accomodate Niagara-1 which can only count insn cycles
27 * in PICH.
28 */
29static u64 picl_value(void)
30{
31 u32 delta = local_cpu_data().clock_tick / HZ;
32
33 return ((u64)((0 - delta) & 0xffffffff)) << 32;
34}
35
36#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
37#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
38 PCR_N2_TOE_OV1 | \
39 (2 << PCR_N2_SL1_SHIFT) | \
40 (0xff << PCR_N2_MASK1_SHIFT))
41
42static u64 pcr_enable;
43
44static void nmi_handler(struct pt_regs *regs)
45{ 23{
46 pcr_ops->write(PCR_PIC_PRIV); 24 struct die_args *args = (struct die_args *)data;
25 int ret = NOTIFY_DONE;
47 26
48 if (nmi_enabled) { 27 switch (val) {
49 oprofile_add_sample(regs, 0); 28 case DIE_NMI:
50 29 oprofile_add_sample(args->regs, 0);
51 write_pic(picl_value()); 30 ret = NOTIFY_STOP;
52 pcr_ops->write(pcr_enable); 31 break;
32 default:
33 break;
53 } 34 }
35 return ret;
54} 36}
55 37
56/* We count "clock cycle" events in the lower 32-bit PIC. 38static struct notifier_block profile_timer_exceptions_nb = {
57 * Then configure it such that it overflows every HZ, and thus 39 .notifier_call = profile_timer_exceptions_notify,
58 * generates a level 15 interrupt at that frequency. 40};
59 */
60static void cpu_nmi_start(void *_unused)
61{
62 pcr_ops->write(PCR_PIC_PRIV);
63 write_pic(picl_value());
64
65 pcr_ops->write(pcr_enable);
66}
67 41
68static void cpu_nmi_stop(void *_unused) 42static int timer_start(void)
69{ 43{
70 pcr_ops->write(PCR_PIC_PRIV); 44 if (register_die_notifier(&profile_timer_exceptions_nb))
45 return 1;
46 nmi_adjust_hz(HZ);
47 return 0;
71} 48}
72 49
73static int nmi_start(void)
74{
75 int err = register_perfctr_intr(nmi_handler);
76
77 if (!err) {
78 nmi_enabled = 1;
79 wmb();
80 err = on_each_cpu(cpu_nmi_start, NULL, 1);
81 if (err) {
82 nmi_enabled = 0;
83 wmb();
84 on_each_cpu(cpu_nmi_stop, NULL, 1);
85 release_perfctr_intr(nmi_handler);
86 }
87 }
88
89 return err;
90}
91 50
92static void nmi_stop(void) 51static void timer_stop(void)
93{ 52{
94 nmi_enabled = 0; 53 nmi_adjust_hz(1);
95 wmb(); 54 unregister_die_notifier(&profile_timer_exceptions_nb);
96 55 synchronize_sched(); /* Allow already-started NMIs to complete. */
97 on_each_cpu(cpu_nmi_stop, NULL, 1);
98 release_perfctr_intr(nmi_handler);
99 synchronize_sched();
100} 56}
101 57
102static int oprofile_nmi_init(struct oprofile_operations *ops) 58static int op_nmi_timer_init(struct oprofile_operations *ops)
103{ 59{
104 switch (tlb_type) { 60 if (!nmi_usable)
105 case hypervisor:
106 pcr_enable = PCR_N2_ENABLE;
107 break;
108
109 case cheetah:
110 case cheetah_plus:
111 pcr_enable = PCR_SUN4U_ENABLE;
112 break;
113
114 default:
115 return -ENODEV; 61 return -ENODEV;
116 }
117 62
118 ops->create_files = NULL; 63 ops->start = timer_start;
119 ops->setup = NULL; 64 ops->stop = timer_stop;
120 ops->shutdown = NULL;
121 ops->start = nmi_start;
122 ops->stop = nmi_stop;
123 ops->cpu_type = "timer"; 65 ops->cpu_type = "timer";
124 66 printk(KERN_INFO "oprofile: Using perfctr NMI timer interrupt.\n");
125 printk(KERN_INFO "oprofile: Using perfctr based NMI timer interrupt.\n");
126
127 return 0; 67 return 0;
128} 68}
129#endif 69#endif
@@ -133,7 +73,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
133 int ret = -ENODEV; 73 int ret = -ENODEV;
134 74
135#ifdef CONFIG_SPARC64 75#ifdef CONFIG_SPARC64
136 ret = oprofile_nmi_init(ops); 76 ret = op_nmi_timer_init(ops);
137 if (!ret) 77 if (!ret)
138 return ret; 78 return ret;
139#endif 79#endif