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