summaryrefslogtreecommitdiffstats
path: root/arch/sparc/oprofile
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-01-29 21:22:47 -0800
committerDavid S. Miller <davem@davemloft.net>2009-01-30 00:03:53 -0800
commite5553a6d04421eec326a629571d696e8e745a0e4 (patch)
treeb6fe49a18135dbe27a464fb78828b2150c679689 /arch/sparc/oprofile
parentc3cf5e8cc56d272f828a66610bb78bbb727b2ce1 (diff)
downloadlinux-e5553a6d04421eec326a629571d696e8e745a0e4.tar.gz
linux-e5553a6d04421eec326a629571d696e8e745a0e4.tar.bz2
linux-e5553a6d04421eec326a629571d696e8e745a0e4.zip
sparc64: Implement NMI watchdog on capable cpus.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/oprofile')
-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 @@
#include <linux/init.h>
#ifdef CONFIG_SPARC64
-#include <asm/hypervisor.h>
-#include <asm/spitfire.h>
-#include <asm/cpudata.h>
-#include <asm/irq.h>
-#include <asm/pcr.h>
+#include <linux/notifier.h>
+#include <linux/rcupdate.h>
+#include <linux/kdebug.h>
+#include <asm/nmi.h>
-static int nmi_enabled;
-
-/* In order to commonize as much of the implementation as
- * possible, we use PICH as our counter. Mostly this is
- * to accomodate Niagara-1 which can only count insn cycles
- * in PICH.
- */
-static u64 picl_value(void)
-{
- u32 delta = local_cpu_data().clock_tick / HZ;
-
- return ((u64)((0 - delta) & 0xffffffff)) << 32;
-}
-
-#define PCR_SUN4U_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE)
-#define PCR_N2_ENABLE (PCR_PIC_PRIV | PCR_STRACE | PCR_UTRACE | \
- PCR_N2_TOE_OV1 | \
- (2 << PCR_N2_SL1_SHIFT) | \
- (0xff << PCR_N2_MASK1_SHIFT))
-
-static u64 pcr_enable;
-
-static void nmi_handler(struct pt_regs *regs)
+static int profile_timer_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
{
- pcr_ops->write(PCR_PIC_PRIV);
+ struct die_args *args = (struct die_args *)data;
+ int ret = NOTIFY_DONE;
- if (nmi_enabled) {
- oprofile_add_sample(regs, 0);
-
- write_pic(picl_value());
- pcr_ops->write(pcr_enable);
+ switch (val) {
+ case DIE_NMI:
+ oprofile_add_sample(args->regs, 0);
+ ret = NOTIFY_STOP;
+ break;
+ default:
+ break;
}
+ return ret;
}
-/* We count "clock cycle" events in the lower 32-bit PIC.
- * Then configure it such that it overflows every HZ, and thus
- * generates a level 15 interrupt at that frequency.
- */
-static void cpu_nmi_start(void *_unused)
-{
- pcr_ops->write(PCR_PIC_PRIV);
- write_pic(picl_value());
-
- pcr_ops->write(pcr_enable);
-}
+static struct notifier_block profile_timer_exceptions_nb = {
+ .notifier_call = profile_timer_exceptions_notify,
+};
-static void cpu_nmi_stop(void *_unused)
+static int timer_start(void)
{
- pcr_ops->write(PCR_PIC_PRIV);
+ if (register_die_notifier(&profile_timer_exceptions_nb))
+ return 1;
+ nmi_adjust_hz(HZ);
+ return 0;
}
-static int nmi_start(void)
-{
- int err = register_perfctr_intr(nmi_handler);
-
- if (!err) {
- nmi_enabled = 1;
- wmb();
- err = on_each_cpu(cpu_nmi_start, NULL, 1);
- if (err) {
- nmi_enabled = 0;
- wmb();
- on_each_cpu(cpu_nmi_stop, NULL, 1);
- release_perfctr_intr(nmi_handler);
- }
- }
-
- return err;
-}
-static void nmi_stop(void)
+static void timer_stop(void)
{
- nmi_enabled = 0;
- wmb();
-
- on_each_cpu(cpu_nmi_stop, NULL, 1);
- release_perfctr_intr(nmi_handler);
- synchronize_sched();
+ nmi_adjust_hz(1);
+ unregister_die_notifier(&profile_timer_exceptions_nb);
+ synchronize_sched(); /* Allow already-started NMIs to complete. */
}
-static int oprofile_nmi_init(struct oprofile_operations *ops)
+static int op_nmi_timer_init(struct oprofile_operations *ops)
{
- switch (tlb_type) {
- case hypervisor:
- pcr_enable = PCR_N2_ENABLE;
- break;
-
- case cheetah:
- case cheetah_plus:
- pcr_enable = PCR_SUN4U_ENABLE;
- break;
-
- default:
+ if (!nmi_usable)
return -ENODEV;
- }
- ops->create_files = NULL;
- ops->setup = NULL;
- ops->shutdown = NULL;
- ops->start = nmi_start;
- ops->stop = nmi_stop;
+ ops->start = timer_start;
+ ops->stop = timer_stop;
ops->cpu_type = "timer";
-
- printk(KERN_INFO "oprofile: Using perfctr based NMI timer interrupt.\n");
-
+ printk(KERN_INFO "oprofile: Using perfctr NMI timer interrupt.\n");
return 0;
}
#endif
@@ -133,7 +73,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
int ret = -ENODEV;
#ifdef CONFIG_SPARC64
- ret = oprofile_nmi_init(ops);
+ ret = op_nmi_timer_init(ops);
if (!ret)
return ret;
#endif