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