FILE
nmi_selftest.c
File preview with syntax highlighting.
linux-6.19.14/arch/x86/kernel/nmi_selftest.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Testsuite for NMI: IPIs 4 * 5 * Started by Don Zickus: 6 * (using lib/locking-selftest.c as a guide) 7 * 8 * Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com> 9 */ 10 11#include <linux/smp.h> 12#include <linux/cpumask.h> 13#include <linux/delay.h> 14#include <linux/init.h> 15#include <linux/percpu.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 24static int __initdata nmi_fail; 25 26/* check to see if NMI IPIs work on this machine */ 27static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __initdata; 28 29static int __initdata testcase_total; 30static int __initdata testcase_successes; 31static int __initdata unexpected_testcase_failures; 32static int __initdata unexpected_testcase_unknowns; 33 34static int __init nmi_unk_cb(unsigned int val, struct pt_regs *regs) 35{ 36 unexpected_testcase_unknowns++; 37 return NMI_HANDLED; 38} 39 40static void __init 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 __initdata); 45} 46 47static void __init cleanup_nmi_testsuite(void) 48{ 49 unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); 50} 51 52static 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 62static 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", __initdata)) { 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 90static 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 98static 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 105static void __init reset_nmi(void) 106{ 107 nmi_fail = 0; 108} 109 110static 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 pr_cont("FAILED |"); 121 else if (nmi_fail == TIMEOUT) 122 pr_cont("TIMEOUT|"); 123 else 124 pr_cont("ERROR |"); 125 dump_stack(); 126 } else { 127 testcase_successes++; 128 pr_cont(" ok |"); 129 } 130 pr_cont("\n"); 131 132 testcase_total++; 133 reset_nmi(); 134} 135 136void __init nmi_selftest(void) 137{ 138 init_nmi_testsuite(); 139 140 /* 141 * Run the testsuite: 142 */ 143 pr_info("----------------\n"); 144 pr_info("| NMI testsuite:\n"); 145 pr_info("--------------------\n"); 146 147 pr_info("%12s:", "remote IPI"); 148 dotest(remote_ipi, SUCCESS); 149 150 pr_info("%12s:", "local IPI"); 151 dotest(local_ipi, SUCCESS); 152 153 cleanup_nmi_testsuite(); 154 155 pr_info("--------------------\n"); 156 if (unexpected_testcase_failures) { 157 pr_info("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n", 158 unexpected_testcase_failures, testcase_total); 159 } else { 160 pr_info("Good, all %3d testcases passed! |\n", 161 testcase_successes); 162 } 163 pr_info("-----------------------------------------------------------------\n"); 164}
~/
Read-only file preview.