-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
yaml --- r: 283543 b: refs/heads/master c: 99e8b9c h: refs/heads/master i: 283541: 0281c82 283539: 9e568a6 283535: 350a571 v: v3
- Loading branch information
Don Zickus
authored and
Ingo Molnar
committed
Dec 5, 2011
1 parent
dfe035e
commit 846f0ba
Showing
6 changed files
with
200 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
--- | ||
refs/heads/master: 3603a2512f9e69dc87914ba922eb4a0812b21cd6 | ||
refs/heads/master: 99e8b9ca90d688c3ac7d3a141b701c9694a93925 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/* | ||
* arch/x86/kernel/nmi-selftest.c | ||
* | ||
* Testsuite for NMI: IPIs | ||
* | ||
* Started by Don Zickus: | ||
* (using lib/locking-selftest.c as a guide) | ||
* | ||
* Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com> | ||
*/ | ||
|
||
#include <linux/smp.h> | ||
#include <linux/cpumask.h> | ||
#include <linux/delay.h> | ||
|
||
#include <asm/apic.h> | ||
#include <asm/nmi.h> | ||
|
||
#define SUCCESS 0 | ||
#define FAILURE 1 | ||
#define TIMEOUT 2 | ||
|
||
static int nmi_fail; | ||
|
||
/* check to see if NMI IPIs work on this machine */ | ||
static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly; | ||
|
||
static int testcase_total; | ||
static int testcase_successes; | ||
static int expected_testcase_failures; | ||
static int unexpected_testcase_failures; | ||
static int unexpected_testcase_unknowns; | ||
|
||
static int nmi_unk_cb(unsigned int val, struct pt_regs *regs) | ||
{ | ||
unexpected_testcase_unknowns++; | ||
return NMI_HANDLED; | ||
} | ||
|
||
static void init_nmi_testsuite(void) | ||
{ | ||
/* trap all the unknown NMIs we may generate */ | ||
register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); | ||
} | ||
|
||
static void cleanup_nmi_testsuite(void) | ||
{ | ||
unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); | ||
} | ||
|
||
static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) | ||
{ | ||
int cpu = raw_smp_processor_id(); | ||
|
||
if (cpumask_test_and_clear_cpu(cpu, to_cpumask(nmi_ipi_mask))) | ||
return NMI_HANDLED; | ||
|
||
return NMI_DONE; | ||
} | ||
|
||
static void test_nmi_ipi(struct cpumask *mask) | ||
{ | ||
unsigned long timeout; | ||
|
||
if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, | ||
NMI_FLAG_FIRST, "nmi_selftest")) { | ||
nmi_fail = FAILURE; | ||
return; | ||
} | ||
|
||
/* sync above data before sending NMI */ | ||
wmb(); | ||
|
||
apic->send_IPI_mask(mask, NMI_VECTOR); | ||
|
||
/* Don't wait longer than a second */ | ||
timeout = USEC_PER_SEC; | ||
while (!cpumask_empty(mask) && timeout--) | ||
udelay(1); | ||
|
||
/* What happens if we timeout, do we still unregister?? */ | ||
unregister_nmi_handler(NMI_LOCAL, "nmi_selftest"); | ||
|
||
if (!timeout) | ||
nmi_fail = TIMEOUT; | ||
return; | ||
} | ||
|
||
static void remote_ipi(void) | ||
{ | ||
cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask); | ||
cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
} | ||
|
||
static void local_ipi(void) | ||
{ | ||
cpumask_clear(to_cpumask(nmi_ipi_mask)); | ||
cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
} | ||
|
||
static void reset_nmi(void) | ||
{ | ||
nmi_fail = 0; | ||
} | ||
|
||
static void dotest(void (*testcase_fn)(void), int expected) | ||
{ | ||
testcase_fn(); | ||
/* | ||
* Filter out expected failures: | ||
*/ | ||
if (nmi_fail != expected) { | ||
unexpected_testcase_failures++; | ||
|
||
if (nmi_fail == FAILURE) | ||
printk("FAILED |"); | ||
else if (nmi_fail == TIMEOUT) | ||
printk("TIMEOUT|"); | ||
else | ||
printk("ERROR |"); | ||
dump_stack(); | ||
} else { | ||
testcase_successes++; | ||
printk(" ok |"); | ||
} | ||
testcase_total++; | ||
|
||
reset_nmi(); | ||
} | ||
|
||
static inline void print_testname(const char *testname) | ||
{ | ||
printk("%12s:", testname); | ||
} | ||
|
||
void nmi_selftest(void) | ||
{ | ||
init_nmi_testsuite(); | ||
|
||
/* | ||
* Run the testsuite: | ||
*/ | ||
printk("----------------\n"); | ||
printk("| NMI testsuite:\n"); | ||
printk("--------------------\n"); | ||
|
||
print_testname("remote IPI"); | ||
dotest(remote_ipi, SUCCESS); | ||
printk("\n"); | ||
print_testname("local IPI"); | ||
dotest(local_ipi, SUCCESS); | ||
printk("\n"); | ||
|
||
cleanup_nmi_testsuite(); | ||
|
||
if (unexpected_testcase_failures) { | ||
printk("--------------------\n"); | ||
printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n", | ||
unexpected_testcase_failures, testcase_total); | ||
printk("-----------------------------------------------------------------\n"); | ||
} else if (expected_testcase_failures && testcase_successes) { | ||
printk("--------------------\n"); | ||
printk("%3d out of %3d testcases failed, as expected. |\n", | ||
expected_testcase_failures, testcase_total); | ||
printk("----------------------------------------------------\n"); | ||
} else if (expected_testcase_failures && !testcase_successes) { | ||
printk("--------------------\n"); | ||
printk("All %3d testcases failed, as expected. |\n", | ||
expected_testcase_failures); | ||
printk("----------------------------------------\n"); | ||
} else { | ||
printk("--------------------\n"); | ||
printk("Good, all %3d testcases passed! |\n", | ||
testcase_successes); | ||
printk("---------------------------------\n"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters