linux/arch/x86/kernel/apic/hw_nmi.c
<<
>>
Prefs
   1/*
   2 *  HW NMI watchdog support
   3 *
   4 *  started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
   5 *
   6 *  Arch specific calls to support NMI watchdog
   7 *
   8 *  Bits copied from original nmi.c file
   9 *
  10 */
  11#include <asm/apic.h>
  12
  13#include <linux/cpumask.h>
  14#include <linux/kdebug.h>
  15#include <linux/notifier.h>
  16#include <linux/kprobes.h>
  17#include <linux/nmi.h>
  18#include <linux/module.h>
  19#include <linux/delay.h>
  20
  21#ifdef CONFIG_HARDLOCKUP_DETECTOR
  22u64 hw_nmi_get_sample_period(int watchdog_thresh)
  23{
  24        return (u64)(cpu_khz) * 1000 * watchdog_thresh;
  25}
  26#endif
  27
  28#ifdef arch_trigger_all_cpu_backtrace
  29/* For reliability, we're prepared to waste bits here. */
  30static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
  31
  32/* "in progress" flag of arch_trigger_all_cpu_backtrace */
  33static unsigned long backtrace_flag;
  34
  35void arch_trigger_all_cpu_backtrace(void)
  36{
  37        int i;
  38
  39        if (test_and_set_bit(0, &backtrace_flag))
  40                /*
  41                 * If there is already a trigger_all_cpu_backtrace() in progress
  42                 * (backtrace_flag == 1), don't output double cpu dump infos.
  43                 */
  44                return;
  45
  46        cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
  47
  48        printk(KERN_INFO "sending NMI to all CPUs:\n");
  49        apic->send_IPI_all(NMI_VECTOR);
  50
  51        /* Wait for up to 10 seconds for all CPUs to do the backtrace */
  52        for (i = 0; i < 10 * 1000; i++) {
  53                if (cpumask_empty(to_cpumask(backtrace_mask)))
  54                        break;
  55                mdelay(1);
  56        }
  57
  58        clear_bit(0, &backtrace_flag);
  59        smp_mb__after_clear_bit();
  60}
  61
  62static int __kprobes
  63arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
  64{
  65        int cpu;
  66
  67        cpu = smp_processor_id();
  68
  69        if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
  70                static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
  71
  72                arch_spin_lock(&lock);
  73                printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
  74                show_regs(regs);
  75                arch_spin_unlock(&lock);
  76                cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
  77                return NMI_HANDLED;
  78        }
  79
  80        return NMI_DONE;
  81}
  82
  83static int __init register_trigger_all_cpu_backtrace(void)
  84{
  85        register_nmi_handler(NMI_LOCAL, arch_trigger_all_cpu_backtrace_handler,
  86                                0, "arch_bt");
  87        return 0;
  88}
  89early_initcall(register_trigger_all_cpu_backtrace);
  90#endif
  91