diff options
| author | David S. Miller <davem@davemloft.net> | 2009-01-30 00:22:47 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2009-01-30 03:03:53 -0500 |
| commit | e5553a6d04421eec326a629571d696e8e745a0e4 (patch) | |
| tree | b6fe49a18135dbe27a464fb78828b2150c679689 /arch/sparc/oprofile | |
| parent | c3cf5e8cc56d272f828a66610bb78bbb727b2ce1 (diff) | |
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.c | 128 |
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 | ||
| 22 | static int nmi_enabled; | 21 | static 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 | */ | ||
| 29 | static 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 | |||
| 42 | static u64 pcr_enable; | ||
| 43 | |||
| 44 | static 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. | 38 | static 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 | */ | ||
| 60 | static 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 | ||
| 68 | static void cpu_nmi_stop(void *_unused) | 42 | static 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 | ||
| 73 | static 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 | ||
| 92 | static void nmi_stop(void) | 51 | static 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 | ||
| 102 | static int oprofile_nmi_init(struct oprofile_operations *ops) | 58 | static 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 |
