aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChen, Gong <gong.chen@linux.intel.com>2015-08-12 12:29:34 -0400
committerIngo Molnar <mingo@kernel.org>2015-08-13 04:12:50 -0400
commit648ed94038c030245a06e4be59744fd5cdc18c40 (patch)
tree85acdf36ada3f85191377b257db353a5590c6f56
parent20d51a426fe9a0d0a63cc3a7488f621c8bac37e1 (diff)
x86/mce: Provide a lockless memory pool to save error records
printk() is not safe to use in MCE context. Add a lockless memory allocator pool to save error records in MCE context. Those records will be issued later, in a printk-safe context. The idea is inspired by the APEI/GHES driver. We're very conservative and allocate only two pages for it but since we're going to use those pages throughout the system's lifetime, we allocate them statically to avoid early boot time allocation woes. Signed-off-by: Chen, Gong <gong.chen@linux.intel.com> [ Rewrite. ] Signed-off-by: Borislav Petkov <bp@suse.de> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Link: http://lkml.kernel.org/r/1439396985-12812-3-git-send-email-bp@alien8.de Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/kernel/cpu/mcheck/Makefile2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-genpool.c99
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-internal.h12
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c8
5 files changed, 120 insertions, 2 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index b3a1a5d77d92..06dbb5da90c6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -955,6 +955,7 @@ config X86_REROUTE_FOR_BROKEN_BOOT_IRQS
955 955
956config X86_MCE 956config X86_MCE
957 bool "Machine Check / overheating reporting" 957 bool "Machine Check / overheating reporting"
958 select GENERIC_ALLOCATOR
958 default y 959 default y
959 ---help--- 960 ---help---
960 Machine Check support allows the processor to notify the 961 Machine Check support allows the processor to notify the
diff --git a/arch/x86/kernel/cpu/mcheck/Makefile b/arch/x86/kernel/cpu/mcheck/Makefile
index bb34b03af252..a3311c886194 100644
--- a/arch/x86/kernel/cpu/mcheck/Makefile
+++ b/arch/x86/kernel/cpu/mcheck/Makefile
@@ -1,4 +1,4 @@
1obj-y = mce.o mce-severity.o 1obj-y = mce.o mce-severity.o mce-genpool.o
2 2
3obj-$(CONFIG_X86_ANCIENT_MCE) += winchip.o p5.o 3obj-$(CONFIG_X86_ANCIENT_MCE) += winchip.o p5.o
4obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o 4obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
diff --git a/arch/x86/kernel/cpu/mcheck/mce-genpool.c b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
new file mode 100644
index 000000000000..0a850100c594
--- /dev/null
+++ b/arch/x86/kernel/cpu/mcheck/mce-genpool.c
@@ -0,0 +1,99 @@
1/*
2 * MCE event pool management in MCE context
3 *
4 * Copyright (C) 2015 Intel Corp.
5 * Author: Chen, Gong <gong.chen@linux.intel.com>
6 *
7 * This file is licensed under GPLv2.
8 */
9#include <linux/smp.h>
10#include <linux/mm.h>
11#include <linux/genalloc.h>
12#include <linux/llist.h>
13#include "mce-internal.h"
14
15/*
16 * printk() is not safe in MCE context. This is a lock-less memory allocator
17 * used to save error information organized in a lock-less list.
18 *
19 * This memory pool is only to be used to save MCE records in MCE context.
20 * MCE events are rare, so a fixed size memory pool should be enough. Use
21 * 2 pages to save MCE events for now (~80 MCE records at most).
22 */
23#define MCE_POOLSZ (2 * PAGE_SIZE)
24
25static struct gen_pool *mce_evt_pool;
26static LLIST_HEAD(mce_event_llist);
27static char gen_pool_buf[MCE_POOLSZ];
28
29void mce_gen_pool_process(void)
30{
31 struct llist_node *head;
32 struct mce_evt_llist *node;
33 struct mce *mce;
34
35 head = llist_del_all(&mce_event_llist);
36 if (!head)
37 return;
38
39 head = llist_reverse_order(head);
40 llist_for_each_entry(node, head, llnode) {
41 mce = &node->mce;
42 atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
43 gen_pool_free(mce_evt_pool, (unsigned long)node, sizeof(*node));
44 }
45}
46
47bool mce_gen_pool_empty(void)
48{
49 return llist_empty(&mce_event_llist);
50}
51
52int mce_gen_pool_add(struct mce *mce)
53{
54 struct mce_evt_llist *node;
55
56 if (!mce_evt_pool)
57 return -EINVAL;
58
59 node = (void *)gen_pool_alloc(mce_evt_pool, sizeof(*node));
60 if (!node) {
61 pr_warn_ratelimited("MCE records pool full!\n");
62 return -ENOMEM;
63 }
64
65 memcpy(&node->mce, mce, sizeof(*mce));
66 llist_add(&node->llnode, &mce_event_llist);
67
68 return 0;
69}
70
71static int mce_gen_pool_create(void)
72{
73 struct gen_pool *tmpp;
74 int ret = -ENOMEM;
75
76 tmpp = gen_pool_create(ilog2(sizeof(struct mce_evt_llist)), -1);
77 if (!tmpp)
78 goto out;
79
80 ret = gen_pool_add(tmpp, (unsigned long)gen_pool_buf, MCE_POOLSZ, -1);
81 if (ret) {
82 gen_pool_destroy(tmpp);
83 goto out;
84 }
85
86 mce_evt_pool = tmpp;
87
88out:
89 return ret;
90}
91
92int mce_gen_pool_init(void)
93{
94 /* Just init mce_gen_pool once. */
95 if (mce_evt_pool)
96 return 0;
97
98 return mce_gen_pool_create();
99}
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index fe32074b865b..ea8b62264c14 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -13,6 +13,8 @@ enum severity_level {
13 MCE_PANIC_SEVERITY, 13 MCE_PANIC_SEVERITY,
14}; 14};
15 15
16extern struct atomic_notifier_head x86_mce_decoder_chain;
17
16#define ATTR_LEN 16 18#define ATTR_LEN 16
17#define INITIAL_CHECK_INTERVAL 5 * 60 /* 5 minutes */ 19#define INITIAL_CHECK_INTERVAL 5 * 60 /* 5 minutes */
18 20
@@ -24,6 +26,16 @@ struct mce_bank {
24 char attrname[ATTR_LEN]; /* attribute name */ 26 char attrname[ATTR_LEN]; /* attribute name */
25}; 27};
26 28
29struct mce_evt_llist {
30 struct llist_node llnode;
31 struct mce mce;
32};
33
34void mce_gen_pool_process(void);
35bool mce_gen_pool_empty(void);
36int mce_gen_pool_add(struct mce *mce);
37int mce_gen_pool_init(void);
38
27extern int (*mce_severity)(struct mce *a, int tolerant, char **msg, bool is_excp); 39extern int (*mce_severity)(struct mce *a, int tolerant, char **msg, bool is_excp);
28struct dentry *mce_get_debugfs_dir(void); 40struct dentry *mce_get_debugfs_dir(void);
29 41
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index df919ff103c3..a41c014e5cde 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -118,7 +118,7 @@ static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
118 * CPU/chipset specific EDAC code can register a notifier call here to print 118 * CPU/chipset specific EDAC code can register a notifier call here to print
119 * MCE errors in a human-readable form. 119 * MCE errors in a human-readable form.
120 */ 120 */
121static ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain); 121ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
122 122
123/* Do initial initialization of a struct mce */ 123/* Do initial initialization of a struct mce */
124void mce_setup(struct mce *m) 124void mce_setup(struct mce *m)
@@ -1731,6 +1731,12 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c)
1731 return; 1731 return;
1732 } 1732 }
1733 1733
1734 if (mce_gen_pool_init()) {
1735 mca_cfg.disabled = true;
1736 pr_emerg("Couldn't allocate MCE records pool!\n");
1737 return;
1738 }
1739
1734 machine_check_vector = do_machine_check; 1740 machine_check_vector = do_machine_check;
1735 1741
1736 __mcheck_cpu_init_generic(); 1742 __mcheck_cpu_init_generic();