root/arch/x86/kernel/nmi_selftest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. DECLARE_BITMAP
  2. init_nmi_testsuite
  3. cleanup_nmi_testsuite
  4. test_nmi_ipi_callback
  5. test_nmi_ipi
  6. remote_ipi
  7. local_ipi
  8. reset_nmi
  9. dotest
  10. print_testname
  11. nmi_selftest

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

/* [<][>][^][v][top][bottom][index][help] */