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 23 static int nmi_fail; 24 25 /* check to see if NMI IPIs work on this machine */ 26 static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly; 27 28 static int testcase_total; 29 static int testcase_successes; 30 static int expected_testcase_failures; 31 static int unexpected_testcase_failures; 32 static int unexpected_testcase_unknowns; 33 34 static int nmi_unk_cb(unsigned int val, struct pt_regs *regs) 35 { 36 unexpected_testcase_unknowns++; 37 return NMI_HANDLED; 38 } 39 40 static 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 46 static void cleanup_nmi_testsuite(void) 47 { 48 unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); 49 } 50 51 static 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 61 static 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 89 static 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 97 static 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 104 static void reset_nmi(void) 105 { 106 nmi_fail = 0; 107 } 108 109 static 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 134 static inline void print_testname(const char *testname) 135 { 136 printk("%12s:", testname); 137 } 138 139 void 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