aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();