aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig4
-rw-r--r--drivers/acpi/acpi_extlog.c46
-rw-r--r--drivers/acpi/apei/Kconfig8
-rw-r--r--drivers/acpi/apei/apei-base.c13
-rw-r--r--drivers/acpi/apei/ghes.c173
-rw-r--r--drivers/acpi/apei/hest.c29
6 files changed, 169 insertions, 104 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index a34a22841002..206942b8d105 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -370,6 +370,7 @@ config ACPI_EXTLOG
370 tristate "Extended Error Log support" 370 tristate "Extended Error Log support"
371 depends on X86_MCE && X86_LOCAL_APIC 371 depends on X86_MCE && X86_LOCAL_APIC
372 select UEFI_CPER 372 select UEFI_CPER
373 select RAS
373 default n 374 default n
374 help 375 help
375 Certain usages such as Predictive Failure Analysis (PFA) require 376 Certain usages such as Predictive Failure Analysis (PFA) require
@@ -384,6 +385,7 @@ config ACPI_EXTLOG
384 385
385 Enhanced MCA Logging allows firmware to provide additional error 386 Enhanced MCA Logging allows firmware to provide additional error
386 information to system software, synchronous with MCE or CMCI. This 387 information to system software, synchronous with MCE or CMCI. This
387 driver adds support for that functionality. 388 driver adds support for that functionality with corresponding
389 tracepoint which carries that information to userspace.
388 390
389endif # ACPI 391endif # ACPI
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c
index 185334114d71..0ad6f389d922 100644
--- a/drivers/acpi/acpi_extlog.c
+++ b/drivers/acpi/acpi_extlog.c
@@ -12,10 +12,12 @@
12#include <linux/cper.h> 12#include <linux/cper.h>
13#include <linux/ratelimit.h> 13#include <linux/ratelimit.h>
14#include <linux/edac.h> 14#include <linux/edac.h>
15#include <linux/ras.h>
15#include <asm/cpu.h> 16#include <asm/cpu.h>
16#include <asm/mce.h> 17#include <asm/mce.h>
17 18
18#include "apei/apei-internal.h" 19#include "apei/apei-internal.h"
20#include <ras/ras_event.h>
19 21
20#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */ 22#define EXT_ELOG_ENTRY_MASK GENMASK_ULL(51, 0) /* elog entry address mask */
21 23
@@ -137,8 +139,12 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
137 struct mce *mce = (struct mce *)data; 139 struct mce *mce = (struct mce *)data;
138 int bank = mce->bank; 140 int bank = mce->bank;
139 int cpu = mce->extcpu; 141 int cpu = mce->extcpu;
140 struct acpi_generic_status *estatus; 142 struct acpi_generic_status *estatus, *tmp;
141 int rc; 143 struct acpi_generic_data *gdata;
144 const uuid_le *fru_id = &NULL_UUID_LE;
145 char *fru_text = "";
146 uuid_le *sec_type;
147 static u32 err_seq;
142 148
143 estatus = extlog_elog_entry_check(cpu, bank); 149 estatus = extlog_elog_entry_check(cpu, bank);
144 if (estatus == NULL) 150 if (estatus == NULL)
@@ -148,8 +154,29 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
148 /* clear record status to enable BIOS to update it again */ 154 /* clear record status to enable BIOS to update it again */
149 estatus->block_status = 0; 155 estatus->block_status = 0;
150 156
151 rc = print_extlog_rcd(NULL, (struct acpi_generic_status *)elog_buf, cpu); 157 tmp = (struct acpi_generic_status *)elog_buf;
158
159 if (!ras_userspace_consumers()) {
160 print_extlog_rcd(NULL, tmp, cpu);
161 goto out;
162 }
163
164 /* log event via trace */
165 err_seq++;
166 gdata = (struct acpi_generic_data *)(tmp + 1);
167 if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
168 fru_id = (uuid_le *)gdata->fru_id;
169 if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
170 fru_text = gdata->fru_text;
171 sec_type = (uuid_le *)gdata->section_type;
172 if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
173 struct cper_sec_mem_err *mem = (void *)(gdata + 1);
174 if (gdata->error_data_length >= sizeof(*mem))
175 trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
176 (u8)gdata->error_severity);
177 }
152 178
179out:
153 return NOTIFY_STOP; 180 return NOTIFY_STOP;
154} 181}
155 182
@@ -196,19 +223,16 @@ static int __init extlog_init(void)
196 u64 cap; 223 u64 cap;
197 int rc; 224 int rc;
198 225
226 rdmsrl(MSR_IA32_MCG_CAP, cap);
227
228 if (!(cap & MCG_ELOG_P) || !extlog_get_l1addr())
229 return -ENODEV;
230
199 if (get_edac_report_status() == EDAC_REPORTING_FORCE) { 231 if (get_edac_report_status() == EDAC_REPORTING_FORCE) {
200 pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n"); 232 pr_warn("Not loading eMCA, error reporting force-enabled through EDAC.\n");
201 return -EPERM; 233 return -EPERM;
202 } 234 }
203 235
204 rc = -ENODEV;
205 rdmsrl(MSR_IA32_MCG_CAP, cap);
206 if (!(cap & MCG_ELOG_P))
207 return rc;
208
209 if (!extlog_get_l1addr())
210 return rc;
211
212 rc = -EINVAL; 236 rc = -EINVAL;
213 /* get L1 header to fetch necessary information */ 237 /* get L1 header to fetch necessary information */
214 l1_hdr_size = sizeof(struct extlog_l1_head); 238 l1_hdr_size = sizeof(struct extlog_l1_head);
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index c4dac7150960..b0140c8fc733 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -1,9 +1,15 @@
1config HAVE_ACPI_APEI
2 bool
3
4config HAVE_ACPI_APEI_NMI
5 bool
6
1config ACPI_APEI 7config ACPI_APEI
2 bool "ACPI Platform Error Interface (APEI)" 8 bool "ACPI Platform Error Interface (APEI)"
3 select MISC_FILESYSTEMS 9 select MISC_FILESYSTEMS
4 select PSTORE 10 select PSTORE
5 select UEFI_CPER 11 select UEFI_CPER
6 depends on X86 12 depends on HAVE_ACPI_APEI
7 help 13 help
8 APEI allows to report errors (for example from the chipset) 14 APEI allows to report errors (for example from the chipset)
9 to the operating system. This improves NMI handling 15 to the operating system. This improves NMI handling
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 8678dfe5366b..2cd7bdd6c8b3 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -745,6 +745,19 @@ struct dentry *apei_get_debugfs_dir(void)
745} 745}
746EXPORT_SYMBOL_GPL(apei_get_debugfs_dir); 746EXPORT_SYMBOL_GPL(apei_get_debugfs_dir);
747 747
748int __weak arch_apei_enable_cmcff(struct acpi_hest_header *hest_hdr,
749 void *data)
750{
751 return 1;
752}
753EXPORT_SYMBOL_GPL(arch_apei_enable_cmcff);
754
755void __weak arch_apei_report_mem_error(int sev,
756 struct cper_sec_mem_err *mem_err)
757{
758}
759EXPORT_SYMBOL_GPL(arch_apei_report_mem_error);
760
748int apei_osc_setup(void) 761int apei_osc_setup(void)
749{ 762{
750 static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c"; 763 static u8 whea_uuid_str[] = "ed855e0c-6c90-47bf-a62a-26de0fc5ad5c";
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index dab7cb7349df..e05d84e7b06d 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -47,11 +47,11 @@
47#include <linux/genalloc.h> 47#include <linux/genalloc.h>
48#include <linux/pci.h> 48#include <linux/pci.h>
49#include <linux/aer.h> 49#include <linux/aer.h>
50#include <linux/nmi.h>
50 51
51#include <acpi/ghes.h> 52#include <acpi/ghes.h>
52#include <asm/mce.h> 53#include <acpi/apei.h>
53#include <asm/tlbflush.h> 54#include <asm/tlbflush.h>
54#include <asm/nmi.h>
55 55
56#include "apei-internal.h" 56#include "apei-internal.h"
57 57
@@ -86,8 +86,6 @@
86bool ghes_disable; 86bool ghes_disable;
87module_param_named(disable, ghes_disable, bool, 0); 87module_param_named(disable, ghes_disable, bool, 0);
88 88
89static int ghes_panic_timeout __read_mostly = 30;
90
91/* 89/*
92 * All error sources notified with SCI shares one notifier function, 90 * All error sources notified with SCI shares one notifier function,
93 * so they need to be linked and checked one by one. This is applied 91 * so they need to be linked and checked one by one. This is applied
@@ -97,16 +95,9 @@ static int ghes_panic_timeout __read_mostly = 30;
97 * list changing, not for traversing. 95 * list changing, not for traversing.
98 */ 96 */
99static LIST_HEAD(ghes_sci); 97static LIST_HEAD(ghes_sci);
100static LIST_HEAD(ghes_nmi);
101static DEFINE_MUTEX(ghes_list_mutex); 98static DEFINE_MUTEX(ghes_list_mutex);
102 99
103/* 100/*
104 * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
105 * mutual exclusion.
106 */
107static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
108
109/*
110 * Because the memory area used to transfer hardware error information 101 * Because the memory area used to transfer hardware error information
111 * from BIOS to Linux can be determined only in NMI, IRQ or timer 102 * from BIOS to Linux can be determined only in NMI, IRQ or timer
112 * handler, but general ioremap can not be used in atomic context, so 103 * handler, but general ioremap can not be used in atomic context, so
@@ -114,12 +105,16 @@ static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
114 */ 105 */
115 106
116/* 107/*
117 * Two virtual pages are used, one for NMI context, the other for 108 * Two virtual pages are used, one for IRQ/PROCESS context, the other for
118 * IRQ/PROCESS context 109 * NMI context (optionally).
119 */ 110 */
120#define GHES_IOREMAP_PAGES 2 111#ifdef CONFIG_HAVE_ACPI_APEI_NMI
121#define GHES_IOREMAP_NMI_PAGE(base) (base) 112#define GHES_IOREMAP_PAGES 2
122#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE) 113#else
114#define GHES_IOREMAP_PAGES 1
115#endif
116#define GHES_IOREMAP_IRQ_PAGE(base) (base)
117#define GHES_IOREMAP_NMI_PAGE(base) ((base) + PAGE_SIZE)
123 118
124/* virtual memory area for atomic ioremap */ 119/* virtual memory area for atomic ioremap */
125static struct vm_struct *ghes_ioremap_area; 120static struct vm_struct *ghes_ioremap_area;
@@ -130,18 +125,8 @@ static struct vm_struct *ghes_ioremap_area;
130static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi); 125static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
131static DEFINE_SPINLOCK(ghes_ioremap_lock_irq); 126static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
132 127
133/*
134 * printk is not safe in NMI context. So in NMI handler, we allocate
135 * required memory from lock-less memory allocator
136 * (ghes_estatus_pool), save estatus into it, put them into lock-less
137 * list (ghes_estatus_llist), then delay printk into IRQ context via
138 * irq_work (ghes_proc_irq_work). ghes_estatus_size_request record
139 * required pool size by all NMI error source.
140 */
141static struct gen_pool *ghes_estatus_pool; 128static struct gen_pool *ghes_estatus_pool;
142static unsigned long ghes_estatus_pool_size_request; 129static unsigned long ghes_estatus_pool_size_request;
143static struct llist_head ghes_estatus_llist;
144static struct irq_work ghes_proc_irq_work;
145 130
146struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE]; 131struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
147static atomic_t ghes_estatus_cache_alloced; 132static atomic_t ghes_estatus_cache_alloced;
@@ -192,7 +177,7 @@ static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
192 177
193 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base)); 178 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
194 unmap_kernel_range_noflush(vaddr, PAGE_SIZE); 179 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
195 __flush_tlb_one(vaddr); 180 arch_apei_flush_tlb_one(vaddr);
196} 181}
197 182
198static void ghes_iounmap_irq(void __iomem *vaddr_ptr) 183static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
@@ -202,7 +187,7 @@ static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
202 187
203 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base)); 188 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
204 unmap_kernel_range_noflush(vaddr, PAGE_SIZE); 189 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
205 __flush_tlb_one(vaddr); 190 arch_apei_flush_tlb_one(vaddr);
206} 191}
207 192
208static int ghes_estatus_pool_init(void) 193static int ghes_estatus_pool_init(void)
@@ -249,11 +234,6 @@ static int ghes_estatus_pool_expand(unsigned long len)
249 return 0; 234 return 0;
250} 235}
251 236
252static void ghes_estatus_pool_shrink(unsigned long len)
253{
254 ghes_estatus_pool_size_request -= PAGE_ALIGN(len);
255}
256
257static struct ghes *ghes_new(struct acpi_hest_generic *generic) 237static struct ghes *ghes_new(struct acpi_hest_generic *generic)
258{ 238{
259 struct ghes *ghes; 239 struct ghes *ghes;
@@ -455,9 +435,7 @@ static void ghes_do_proc(struct ghes *ghes,
455 mem_err = (struct cper_sec_mem_err *)(gdata+1); 435 mem_err = (struct cper_sec_mem_err *)(gdata+1);
456 ghes_edac_report_mem_error(ghes, sev, mem_err); 436 ghes_edac_report_mem_error(ghes, sev, mem_err);
457 437
458#ifdef CONFIG_X86_MCE 438 arch_apei_report_mem_error(sev, mem_err);
459 apei_mce_report_mem_error(sev, mem_err);
460#endif
461 ghes_handle_memory_failure(gdata, sev); 439 ghes_handle_memory_failure(gdata, sev);
462 } 440 }
463#ifdef CONFIG_ACPI_APEI_PCIEAER 441#ifdef CONFIG_ACPI_APEI_PCIEAER
@@ -734,6 +712,32 @@ static int ghes_notify_sci(struct notifier_block *this,
734 return ret; 712 return ret;
735} 713}
736 714
715static struct notifier_block ghes_notifier_sci = {
716 .notifier_call = ghes_notify_sci,
717};
718
719#ifdef CONFIG_HAVE_ACPI_APEI_NMI
720/*
721 * printk is not safe in NMI context. So in NMI handler, we allocate
722 * required memory from lock-less memory allocator
723 * (ghes_estatus_pool), save estatus into it, put them into lock-less
724 * list (ghes_estatus_llist), then delay printk into IRQ context via
725 * irq_work (ghes_proc_irq_work). ghes_estatus_size_request record
726 * required pool size by all NMI error source.
727 */
728static struct llist_head ghes_estatus_llist;
729static struct irq_work ghes_proc_irq_work;
730
731/*
732 * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
733 * mutual exclusion.
734 */
735static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
736
737static LIST_HEAD(ghes_nmi);
738
739static int ghes_panic_timeout __read_mostly = 30;
740
737static struct llist_node *llist_nodes_reverse(struct llist_node *llnode) 741static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
738{ 742{
739 struct llist_node *next, *tail = NULL; 743 struct llist_node *next, *tail = NULL;
@@ -877,10 +881,6 @@ out:
877 return ret; 881 return ret;
878} 882}
879 883
880static struct notifier_block ghes_notifier_sci = {
881 .notifier_call = ghes_notify_sci,
882};
883
884static unsigned long ghes_esource_prealloc_size( 884static unsigned long ghes_esource_prealloc_size(
885 const struct acpi_hest_generic *generic) 885 const struct acpi_hest_generic *generic)
886{ 886{
@@ -896,11 +896,71 @@ static unsigned long ghes_esource_prealloc_size(
896 return prealloc_size; 896 return prealloc_size;
897} 897}
898 898
899static void ghes_estatus_pool_shrink(unsigned long len)
900{
901 ghes_estatus_pool_size_request -= PAGE_ALIGN(len);
902}
903
904static void ghes_nmi_add(struct ghes *ghes)
905{
906 unsigned long len;
907
908 len = ghes_esource_prealloc_size(ghes->generic);
909 ghes_estatus_pool_expand(len);
910 mutex_lock(&ghes_list_mutex);
911 if (list_empty(&ghes_nmi))
912 register_nmi_handler(NMI_LOCAL, ghes_notify_nmi, 0, "ghes");
913 list_add_rcu(&ghes->list, &ghes_nmi);
914 mutex_unlock(&ghes_list_mutex);
915}
916
917static void ghes_nmi_remove(struct ghes *ghes)
918{
919 unsigned long len;
920
921 mutex_lock(&ghes_list_mutex);
922 list_del_rcu(&ghes->list);
923 if (list_empty(&ghes_nmi))
924 unregister_nmi_handler(NMI_LOCAL, "ghes");
925 mutex_unlock(&ghes_list_mutex);
926 /*
927 * To synchronize with NMI handler, ghes can only be
928 * freed after NMI handler finishes.
929 */
930 synchronize_rcu();
931 len = ghes_esource_prealloc_size(ghes->generic);
932 ghes_estatus_pool_shrink(len);
933}
934
935static void ghes_nmi_init_cxt(void)
936{
937 init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq);
938}
939#else /* CONFIG_HAVE_ACPI_APEI_NMI */
940static inline void ghes_nmi_add(struct ghes *ghes)
941{
942 pr_err(GHES_PFX "ID: %d, trying to add NMI notification which is not supported!\n",
943 ghes->generic->header.source_id);
944 BUG();
945}
946
947static inline void ghes_nmi_remove(struct ghes *ghes)
948{
949 pr_err(GHES_PFX "ID: %d, trying to remove NMI notification which is not supported!\n",
950 ghes->generic->header.source_id);
951 BUG();
952}
953
954static inline void ghes_nmi_init_cxt(void)
955{
956}
957#endif /* CONFIG_HAVE_ACPI_APEI_NMI */
958
899static int ghes_probe(struct platform_device *ghes_dev) 959static int ghes_probe(struct platform_device *ghes_dev)
900{ 960{
901 struct acpi_hest_generic *generic; 961 struct acpi_hest_generic *generic;
902 struct ghes *ghes = NULL; 962 struct ghes *ghes = NULL;
903 unsigned long len; 963
904 int rc = -EINVAL; 964 int rc = -EINVAL;
905 965
906 generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data; 966 generic = *(struct acpi_hest_generic **)ghes_dev->dev.platform_data;
@@ -911,7 +971,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
911 case ACPI_HEST_NOTIFY_POLLED: 971 case ACPI_HEST_NOTIFY_POLLED:
912 case ACPI_HEST_NOTIFY_EXTERNAL: 972 case ACPI_HEST_NOTIFY_EXTERNAL:
913 case ACPI_HEST_NOTIFY_SCI: 973 case ACPI_HEST_NOTIFY_SCI:
974 break;
914 case ACPI_HEST_NOTIFY_NMI: 975 case ACPI_HEST_NOTIFY_NMI:
976 if (!IS_ENABLED(CONFIG_HAVE_ACPI_APEI_NMI)) {
977 pr_warn(GHES_PFX "Generic hardware error source: %d notified via NMI interrupt is not supported!\n",
978 generic->header.source_id);
979 goto err;
980 }
915 break; 981 break;
916 case ACPI_HEST_NOTIFY_LOCAL: 982 case ACPI_HEST_NOTIFY_LOCAL:
917 pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n", 983 pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
@@ -972,14 +1038,7 @@ static int ghes_probe(struct platform_device *ghes_dev)
972 mutex_unlock(&ghes_list_mutex); 1038 mutex_unlock(&ghes_list_mutex);
973 break; 1039 break;
974 case ACPI_HEST_NOTIFY_NMI: 1040 case ACPI_HEST_NOTIFY_NMI:
975 len = ghes_esource_prealloc_size(generic); 1041 ghes_nmi_add(ghes);
976 ghes_estatus_pool_expand(len);
977 mutex_lock(&ghes_list_mutex);
978 if (list_empty(&ghes_nmi))
979 register_nmi_handler(NMI_LOCAL, ghes_notify_nmi, 0,
980 "ghes");
981 list_add_rcu(&ghes->list, &ghes_nmi);
982 mutex_unlock(&ghes_list_mutex);
983 break; 1042 break;
984 default: 1043 default:
985 BUG(); 1044 BUG();
@@ -1001,7 +1060,6 @@ static int ghes_remove(struct platform_device *ghes_dev)
1001{ 1060{
1002 struct ghes *ghes; 1061 struct ghes *ghes;
1003 struct acpi_hest_generic *generic; 1062 struct acpi_hest_generic *generic;
1004 unsigned long len;
1005 1063
1006 ghes = platform_get_drvdata(ghes_dev); 1064 ghes = platform_get_drvdata(ghes_dev);
1007 generic = ghes->generic; 1065 generic = ghes->generic;
@@ -1022,18 +1080,7 @@ static int ghes_remove(struct platform_device *ghes_dev)
1022 mutex_unlock(&ghes_list_mutex); 1080 mutex_unlock(&ghes_list_mutex);
1023 break; 1081 break;
1024 case ACPI_HEST_NOTIFY_NMI: 1082 case ACPI_HEST_NOTIFY_NMI:
1025 mutex_lock(&ghes_list_mutex); 1083 ghes_nmi_remove(ghes);
1026 list_del_rcu(&ghes->list);
1027 if (list_empty(&ghes_nmi))
1028 unregister_nmi_handler(NMI_LOCAL, "ghes");
1029 mutex_unlock(&ghes_list_mutex);
1030 /*
1031 * To synchronize with NMI handler, ghes can only be
1032 * freed after NMI handler finishes.
1033 */
1034 synchronize_rcu();
1035 len = ghes_esource_prealloc_size(generic);
1036 ghes_estatus_pool_shrink(len);
1037 break; 1084 break;
1038 default: 1085 default:
1039 BUG(); 1086 BUG();
@@ -1077,7 +1124,7 @@ static int __init ghes_init(void)
1077 return -EINVAL; 1124 return -EINVAL;
1078 } 1125 }
1079 1126
1080 init_irq_work(&ghes_proc_irq_work, ghes_proc_in_irq); 1127 ghes_nmi_init_cxt();
1081 1128
1082 rc = ghes_ioremap_init(); 1129 rc = ghes_ioremap_init();
1083 if (rc) 1130 if (rc)
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index f5e37f32c71f..06e9b411a0a2 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -36,7 +36,6 @@
36#include <linux/io.h> 36#include <linux/io.h>
37#include <linux/platform_device.h> 37#include <linux/platform_device.h>
38#include <acpi/apei.h> 38#include <acpi/apei.h>
39#include <asm/mce.h>
40 39
41#include "apei-internal.h" 40#include "apei-internal.h"
42 41
@@ -128,33 +127,7 @@ EXPORT_SYMBOL_GPL(apei_hest_parse);
128 */ 127 */
129static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data) 128static int __init hest_parse_cmc(struct acpi_hest_header *hest_hdr, void *data)
130{ 129{
131#ifdef CONFIG_X86_MCE 130 return arch_apei_enable_cmcff(hest_hdr, data);
132 int i;
133 struct acpi_hest_ia_corrected *cmc;
134 struct acpi_hest_ia_error_bank *mc_bank;
135
136 if (hest_hdr->type != ACPI_HEST_TYPE_IA32_CORRECTED_CHECK)
137 return 0;
138
139 cmc = (struct acpi_hest_ia_corrected *)hest_hdr;
140 if (!cmc->enabled)
141 return 0;
142
143 /*
144 * We expect HEST to provide a list of MC banks that report errors
145 * in firmware first mode. Otherwise, return non-zero value to
146 * indicate that we are done parsing HEST.
147 */
148 if (!(cmc->flags & ACPI_HEST_FIRMWARE_FIRST) || !cmc->num_hardware_banks)
149 return 1;
150
151 pr_info(HEST_PFX "Enabling Firmware First mode for corrected errors.\n");
152
153 mc_bank = (struct acpi_hest_ia_error_bank *)(cmc + 1);
154 for (i = 0; i < cmc->num_hardware_banks; i++, mc_bank++)
155 mce_disable_bank(mc_bank->bank_number);
156#endif
157 return 1;
158} 131}
159 132
160struct ghes_arr { 133struct ghes_arr {