linux/arch/x86/kernel/nmi_selftest.c
<<
>>
Prefs
   1/*
   2 * arch/x86/kernel/nmi-selftest.c
   3 *
   4 * Testsuite for NMI: IPIs
   5 *
   6 * Started by Don Zickus:
   7 * (using lib/locking-selftest.c as a guide)
   8 *
   9 *   Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com>
  10 */
  11
  12#include <linux/smp.h>
  13#include <linux/cpumask.h>
  14#include <linux/delay.h>
  15#include <linux/init.h>
  16#include <linux/percpu.h>
  17
  18#include <asm/apic.h>
  19#include <asm/nmi.h>
  20
  21#define SUCCESS         0
  22#define FAILURE         1
  23#define TIMEOUT         2
  24
  25static int __initdata nmi_fail;
  26
  27/* check to see if NMI IPIs work on this machine */
  28static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata;
  29
  30static int __initdata testcase_total;
  31static int __initdata testcase_successes;
  32static int __initdata expected_testcase_failures;
  33static int __initdata unexpected_testcase_failures;
  34static int __initdata unexpected_testcase_unknowns;
  35
  36static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs)
  37{
  38        unexpected_testcase_unknowns++;
  39        return NMI_HANDLED;
  40}
  41
  42static void __init init_nmi_testsuite(void)
  43{
  44        /* trap all the unknown NMIs we may generate */
  45        register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk",
  46                        __initdata);
  47}
  48
  49static void __init cleanup_nmi_testsuite(void)
  50{
  51        unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk");
  52}
  53
  54static int __init test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs)
  55{
  56        int cpu = raw_smp_processor_id();
  57
  58        if (cpumask_test_and_clear_cpu(cpu, to_cpumask(nmi_ipi_mask)))
  59                return NMI_HANDLED;
  60
  61        return NMI_DONE;
  62}
  63
  64static void __init test_nmi_ipi(struct cpumask *mask)
  65{
  66        unsigned long timeout;
  67
  68        if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback,
  69                                 NMI_FLAG_FIRST, "nmi_selftest", __initdata)) {
  70                nmi_fail = FAILURE;
  71                return;
  72        }
  73
  74        /* sync above data before sending NMI */
  75        wmb();
  76
  77        apic->send_IPI_mask(mask, NMI_VECTOR);
  78
  79        /* Don't wait longer than a second */
  80        timeout = USEC_PER_SEC;
  81        while (!cpumask_empty(mask) && --timeout)
  82                udelay(1);
  83
  84        /* What happens if we timeout, do we still unregister?? */
  85        unregister_nmi_handler(NMI_LOCAL, "nmi_selftest");
  86
  87        if (!timeout)
  88                nmi_fail = TIMEOUT;
  89        return;
  90}
  91
  92static void __init remote_ipi(void)
  93{
  94        cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask);
  95        cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
  96        if (!cpumask_empty(to_cpumask(nmi_ipi_mask)))
  97                test_nmi_ipi(to_cpumask(nmi_ipi_mask));
  98}
  99
 100static void __init local_ipi(void)
 101{
 102        cpumask_clear(to_cpumask(nmi_ipi_mask));
 103        cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask));
 104        test_nmi_ipi(to_cpumask(nmi_ipi_mask));
 105}
 106
 107static void __init reset_nmi(void)
 108{
 109        nmi_fail = 0;
 110}
 111
 112static void __init dotest(void (*testcase_fn)(void), int expected)
 113{
 114        testcase_fn();
 115        /*
 116         * Filter out expected failures:
 117         */
 118        if (nmi_fail != expected) {
 119                unexpected_testcase_failures++;
 120
 121                if (nmi_fail == FAILURE)
 122                        printk(KERN_CONT "FAILED |");
 123                else if (nmi_fail == TIMEOUT)
 124                        printk(KERN_CONT "TIMEOUT|");
 125                else
 126                        printk(KERN_CONT "ERROR  |");
 127                dump_stack();
 128        } else {
 129                testcase_successes++;
 130                printk(KERN_CONT "  ok  |");
 131        }
 132        testcase_total++;
 133
 134        reset_nmi();
 135}
 136
 137static inline void __init print_testname(const char *testname)
 138{
 139        printk("%12s:", testname);
 140}
 141
 142void __init nmi_selftest(void)
 143{
 144        init_nmi_testsuite();
 145
 146        /*
 147         * Run the testsuite:
 148         */
 149        printk("----------------\n");
 150        printk("| NMI testsuite:\n");
 151        printk("--------------------\n");
 152
 153        print_testname("remote IPI");
 154        dotest(remote_ipi, SUCCESS);
 155        printk(KERN_CONT "\n");
 156        print_testname("local IPI");
 157        dotest(local_ipi, SUCCESS);
 158        printk(KERN_CONT "\n");
 159
 160        cleanup_nmi_testsuite();
 161
 162        if (unexpected_testcase_failures) {
 163                printk("--------------------\n");
 164                printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n",
 165                        unexpected_testcase_failures, testcase_total);
 166                printk("-----------------------------------------------------------------\n");
 167        } else if (expected_testcase_failures && testcase_successes) {
 168                printk("--------------------\n");
 169                printk("%3d out of %3d testcases failed, as expected. |\n",
 170                        expected_testcase_failures, testcase_total);
 171                printk("----------------------------------------------------\n");
 172        } else if (expected_testcase_failures && !testcase_successes) {
 173                printk("--------------------\n");
 174                printk("All %3d testcases failed, as expected. |\n",
 175                        expected_testcase_failures);
 176                printk("----------------------------------------\n");
 177        } else {
 178                printk("--------------------\n");
 179                printk("Good, all %3d testcases passed! |\n",
 180                        testcase_successes);
 181                printk("---------------------------------\n");
 182        }
 183}
 184