/root/src/xen/xen/arch/x86/cpu/mcheck/non-fatal.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Non Fatal Machine Check Exception Reporting |
3 | | * |
4 | | * (C) Copyright 2002 Dave Jones. <davej@codemonkey.org.uk> |
5 | | * |
6 | | * This file contains routines to check for non-fatal MCEs every 15s |
7 | | * |
8 | | */ |
9 | | |
10 | | #include <xen/init.h> |
11 | | #include <xen/types.h> |
12 | | #include <xen/kernel.h> |
13 | | #include <xen/smp.h> |
14 | | #include <xen/timer.h> |
15 | | #include <xen/errno.h> |
16 | | #include <xen/event.h> |
17 | | #include <xen/sched.h> |
18 | | #include <asm/processor.h> |
19 | | #include <asm/system.h> |
20 | | #include <asm/msr.h> |
21 | | |
22 | | #include "mce.h" |
23 | | #include "vmce.h" |
24 | | |
25 | | static struct timer mce_timer; |
26 | | |
27 | 1 | #define MCE_PERIOD MILLISECS(8000) |
28 | 6 | #define MCE_PERIOD_MIN MILLISECS(2000) |
29 | 11 | #define MCE_PERIOD_MAX MILLISECS(16000) |
30 | | |
31 | | static uint64_t period = MCE_PERIOD; |
32 | | static int adjust = 0; |
33 | | static int variable_period = 1; |
34 | | |
35 | | static void mce_checkregs (void *info) |
36 | 44 | { |
37 | 44 | mctelem_cookie_t mctc; |
38 | 44 | struct mca_summary bs; |
39 | 44 | static uint64_t dumpcount = 0; |
40 | 44 | |
41 | 44 | mctc = mcheck_mca_logout(MCA_POLLER, __get_cpu_var(poll_bankmask), &bs, NULL); |
42 | 44 | |
43 | 44 | if (bs.errcnt && mctc != NULL) { |
44 | 0 | adjust++; |
45 | 0 |
|
46 | 0 | /* If Dom0 enabled the VIRQ_MCA event, then notify it. |
47 | 0 | * Otherwise, if dom0 has had plenty of time to register |
48 | 0 | * the virq handler but still hasn't then dump telemetry |
49 | 0 | * to the Xen console. The call count may be incremented |
50 | 0 | * on multiple cpus at once and is indicative only - just |
51 | 0 | * a simple-minded attempt to avoid spamming the console |
52 | 0 | * for corrected errors in early startup. |
53 | 0 | */ |
54 | 0 |
|
55 | 0 | if (dom0_vmce_enabled()) { |
56 | 0 | mctelem_commit(mctc); |
57 | 0 | send_global_virq(VIRQ_MCA); |
58 | 0 | } else if (++dumpcount >= 10) { |
59 | 0 | x86_mcinfo_dump((struct mc_info *)mctelem_dataptr(mctc)); |
60 | 0 | mctelem_dismiss(mctc); |
61 | 0 | } else { |
62 | 0 | mctelem_dismiss(mctc); |
63 | 0 | } |
64 | 44 | } else if (mctc != NULL) { |
65 | 0 | mctelem_dismiss(mctc); |
66 | 0 | } |
67 | 44 | } |
68 | | |
69 | | static void mce_work_fn(void *data) |
70 | 6 | { |
71 | 6 | on_each_cpu(mce_checkregs, NULL, 1); |
72 | 6 | |
73 | 6 | if (variable_period) { |
74 | 6 | if (adjust) |
75 | 0 | period /= (adjust + 1); |
76 | 6 | else |
77 | 6 | period *= 2; |
78 | 6 | if (period > MCE_PERIOD_MAX) |
79 | 5 | period = MCE_PERIOD_MAX; |
80 | 6 | if (period < MCE_PERIOD_MIN) |
81 | 0 | period = MCE_PERIOD_MIN; |
82 | 6 | } |
83 | 6 | |
84 | 6 | set_timer(&mce_timer, NOW() + period); |
85 | 6 | adjust = 0; |
86 | 6 | } |
87 | | |
88 | | static int __init init_nonfatal_mce_checker(void) |
89 | 1 | { |
90 | 1 | struct cpuinfo_x86 *c = &boot_cpu_data; |
91 | 1 | |
92 | 1 | /* Check for MCE support */ |
93 | 1 | if (!opt_mce || !mce_available(c)) |
94 | 0 | return -ENODEV; |
95 | 1 | |
96 | 1 | if (__get_cpu_var(poll_bankmask) == NULL) |
97 | 0 | return -EINVAL; |
98 | 1 | |
99 | 1 | /* |
100 | 1 | * Check for non-fatal errors every MCE_RATE s |
101 | 1 | */ |
102 | 1 | switch (c->x86_vendor) { |
103 | 0 | case X86_VENDOR_AMD: |
104 | 0 | /* Assume we are on K8 or newer AMD CPU here */ |
105 | 0 | amd_nonfatal_mcheck_init(c); |
106 | 0 | break; |
107 | 0 |
|
108 | 1 | case X86_VENDOR_INTEL: |
109 | 1 | init_timer(&mce_timer, mce_work_fn, NULL, 0); |
110 | 1 | set_timer(&mce_timer, NOW() + MCE_PERIOD); |
111 | 1 | break; |
112 | 1 | } |
113 | 1 | |
114 | 1 | printk(KERN_INFO "mcheck_poll: Machine check polling timer started.\n"); |
115 | 1 | return 0; |
116 | 1 | } |
117 | | __initcall(init_nonfatal_mce_checker); |