aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei/ghes.c
diff options
context:
space:
mode:
authorHuang Ying <ying.huang@intel.com>2011-01-12 01:44:55 -0500
committerLen Brown <len.brown@intel.com>2011-01-12 03:06:19 -0500
commit81e88fdc432a1552401d6e91a984dcccce72b8dc (patch)
tree41ef511cda7ddf6b96f8d923ffceff74651a5790 /drivers/acpi/apei/ghes.c
parent32c361f574f85fa47600d84900598e2efc99082e (diff)
ACPI, APEI, Generic Hardware Error Source POLL/IRQ/NMI notification type support
Generic Hardware Error Source provides a way to report platform hardware errors (such as that from chipset). It works in so called "Firmware First" mode, that is, hardware errors are reported to firmware firstly, then reported to Linux by firmware. This way, some non-standard hardware error registers or non-standard hardware link can be checked by firmware to produce more valuable hardware error information for Linux. This patch adds POLL/IRQ/NMI notification types support. Because the memory area used to transfer hardware error information from BIOS to Linux can be determined only in NMI, IRQ or timer handler, but general ioremap can not be used in atomic context, so a special version of atomic ioremap is implemented for that. Known issue: - Error information can not be printed for recoverable errors notified via NMI, because printk is not NMI-safe. Will fix this via delay printing to IRQ context via irq_work or make printk NMI-safe. v2: - adjust printk format per comments. Signed-off-by: Huang Ying <ying.huang@intel.com> Reviewed-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/apei/ghes.c')
-rw-r--r--drivers/acpi/apei/ghes.c406
1 files changed, 322 insertions, 84 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 51905d07a4d9..d1d484d4a06a 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -12,10 +12,6 @@
12 * For more information about Generic Hardware Error Source, please 12 * For more information about Generic Hardware Error Source, please
13 * refer to ACPI Specification version 4.0, section 17.3.2.6 13 * refer to ACPI Specification version 4.0, section 17.3.2.6
14 * 14 *
15 * Now, only SCI notification type and memory errors are
16 * supported. More notification type and hardware error type will be
17 * added later.
18 *
19 * Copyright 2010 Intel Corp. 15 * Copyright 2010 Intel Corp.
20 * Author: Huang Ying <ying.huang@intel.com> 16 * Author: Huang Ying <ying.huang@intel.com>
21 * 17 *
@@ -39,15 +35,18 @@
39#include <linux/acpi.h> 35#include <linux/acpi.h>
40#include <linux/io.h> 36#include <linux/io.h>
41#include <linux/interrupt.h> 37#include <linux/interrupt.h>
38#include <linux/timer.h>
42#include <linux/cper.h> 39#include <linux/cper.h>
43#include <linux/kdebug.h> 40#include <linux/kdebug.h>
44#include <linux/platform_device.h> 41#include <linux/platform_device.h>
45#include <linux/mutex.h> 42#include <linux/mutex.h>
46#include <linux/ratelimit.h> 43#include <linux/ratelimit.h>
44#include <linux/vmalloc.h>
47#include <acpi/apei.h> 45#include <acpi/apei.h>
48#include <acpi/atomicio.h> 46#include <acpi/atomicio.h>
49#include <acpi/hed.h> 47#include <acpi/hed.h>
50#include <asm/mce.h> 48#include <asm/mce.h>
49#include <asm/tlbflush.h>
51 50
52#include "apei-internal.h" 51#include "apei-internal.h"
53 52
@@ -56,42 +55,131 @@
56#define GHES_ESTATUS_MAX_SIZE 65536 55#define GHES_ESTATUS_MAX_SIZE 65536
57 56
58/* 57/*
59 * One struct ghes is created for each generic hardware error 58 * One struct ghes is created for each generic hardware error source.
60 * source.
61 *
62 * It provides the context for APEI hardware error timer/IRQ/SCI/NMI 59 * It provides the context for APEI hardware error timer/IRQ/SCI/NMI
63 * handler. Handler for one generic hardware error source is only 60 * handler.
64 * triggered after the previous one is done. So handler can uses
65 * struct ghes without locking.
66 * 61 *
67 * estatus: memory buffer for error status block, allocated during 62 * estatus: memory buffer for error status block, allocated during
68 * HEST parsing. 63 * HEST parsing.
69 */ 64 */
70#define GHES_TO_CLEAR 0x0001 65#define GHES_TO_CLEAR 0x0001
66#define GHES_EXITING 0x0002
71 67
72struct ghes { 68struct ghes {
73 struct acpi_hest_generic *generic; 69 struct acpi_hest_generic *generic;
74 struct acpi_hest_generic_status *estatus; 70 struct acpi_hest_generic_status *estatus;
75 struct list_head list;
76 u64 buffer_paddr; 71 u64 buffer_paddr;
77 unsigned long flags; 72 unsigned long flags;
73 union {
74 struct list_head list;
75 struct timer_list timer;
76 unsigned int irq;
77 };
78}; 78};
79 79
80static int ghes_panic_timeout __read_mostly = 30;
81
80/* 82/*
81 * Error source lists, one list for each notification method. The 83 * All error sources notified with SCI shares one notifier function,
82 * members in lists are struct ghes. 84 * so they need to be linked and checked one by one. This is applied
85 * to NMI too.
83 * 86 *
84 * The list members are only added in HEST parsing and deleted during 87 * RCU is used for these lists, so ghes_list_mutex is only used for
85 * module_exit, that is, single-threaded. So no lock is needed for 88 * list changing, not for traversing.
86 * that.
87 *
88 * But the mutual exclusion is needed between members adding/deleting
89 * and timer/IRQ/SCI/NMI handler, which may traverse the list. RCU is
90 * used for that.
91 */ 89 */
92static LIST_HEAD(ghes_sci); 90static LIST_HEAD(ghes_sci);
91static LIST_HEAD(ghes_nmi);
93static DEFINE_MUTEX(ghes_list_mutex); 92static DEFINE_MUTEX(ghes_list_mutex);
94 93
94/*
95 * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
96 * mutual exclusion.
97 */
98static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
99
100/*
101 * Because the memory area used to transfer hardware error information
102 * from BIOS to Linux can be determined only in NMI, IRQ or timer
103 * handler, but general ioremap can not be used in atomic context, so
104 * a special version of atomic ioremap is implemented for that.
105 */
106
107/*
108 * Two virtual pages are used, one for NMI context, the other for
109 * IRQ/PROCESS context
110 */
111#define GHES_IOREMAP_PAGES 2
112#define GHES_IOREMAP_NMI_PAGE(base) (base)
113#define GHES_IOREMAP_IRQ_PAGE(base) ((base) + PAGE_SIZE)
114
115/* virtual memory area for atomic ioremap */
116static struct vm_struct *ghes_ioremap_area;
117/*
118 * These 2 spinlock is used to prevent atomic ioremap virtual memory
119 * area from being mapped simultaneously.
120 */
121static DEFINE_RAW_SPINLOCK(ghes_ioremap_lock_nmi);
122static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
123
124static int ghes_ioremap_init(void)
125{
126 ghes_ioremap_area = __get_vm_area(PAGE_SIZE * GHES_IOREMAP_PAGES,
127 VM_IOREMAP, VMALLOC_START, VMALLOC_END);
128 if (!ghes_ioremap_area) {
129 pr_err(GHES_PFX "Failed to allocate virtual memory area for atomic ioremap.\n");
130 return -ENOMEM;
131 }
132
133 return 0;
134}
135
136static void ghes_ioremap_exit(void)
137{
138 free_vm_area(ghes_ioremap_area);
139}
140
141static void __iomem *ghes_ioremap_pfn_nmi(u64 pfn)
142{
143 unsigned long vaddr;
144
145 vaddr = (unsigned long)GHES_IOREMAP_NMI_PAGE(ghes_ioremap_area->addr);
146 ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
147 pfn << PAGE_SHIFT, PAGE_KERNEL);
148
149 return (void __iomem *)vaddr;
150}
151
152static void __iomem *ghes_ioremap_pfn_irq(u64 pfn)
153{
154 unsigned long vaddr;
155
156 vaddr = (unsigned long)GHES_IOREMAP_IRQ_PAGE(ghes_ioremap_area->addr);
157 ioremap_page_range(vaddr, vaddr + PAGE_SIZE,
158 pfn << PAGE_SHIFT, PAGE_KERNEL);
159
160 return (void __iomem *)vaddr;
161}
162
163static void ghes_iounmap_nmi(void __iomem *vaddr_ptr)
164{
165 unsigned long vaddr = (unsigned long __force)vaddr_ptr;
166 void *base = ghes_ioremap_area->addr;
167
168 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_NMI_PAGE(base));
169 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
170 __flush_tlb_one(vaddr);
171}
172
173static void ghes_iounmap_irq(void __iomem *vaddr_ptr)
174{
175 unsigned long vaddr = (unsigned long __force)vaddr_ptr;
176 void *base = ghes_ioremap_area->addr;
177
178 BUG_ON(vaddr != (unsigned long)GHES_IOREMAP_IRQ_PAGE(base));
179 unmap_kernel_range_noflush(vaddr, PAGE_SIZE);
180 __flush_tlb_one(vaddr);
181}
182
95static struct ghes *ghes_new(struct acpi_hest_generic *generic) 183static struct ghes *ghes_new(struct acpi_hest_generic *generic)
96{ 184{
97 struct ghes *ghes; 185 struct ghes *ghes;
@@ -102,7 +190,6 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
102 if (!ghes) 190 if (!ghes)
103 return ERR_PTR(-ENOMEM); 191 return ERR_PTR(-ENOMEM);
104 ghes->generic = generic; 192 ghes->generic = generic;
105 INIT_LIST_HEAD(&ghes->list);
106 rc = acpi_pre_map_gar(&generic->error_status_address); 193 rc = acpi_pre_map_gar(&generic->error_status_address);
107 if (rc) 194 if (rc)
108 goto err_free; 195 goto err_free;
@@ -159,22 +246,41 @@ static inline int ghes_severity(int severity)
159 } 246 }
160} 247}
161 248
162/* SCI handler run in work queue, so ioremap can be used here */ 249static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
163static int ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len, 250 int from_phys)
164 int from_phys)
165{ 251{
166 void *vaddr; 252 void __iomem *vaddr;
167 253 unsigned long flags = 0;
168 vaddr = ioremap_cache(paddr, len); 254 int in_nmi = in_nmi();
169 if (!vaddr) 255 u64 offset;
170 return -ENOMEM; 256 u32 trunk;
171 if (from_phys) 257
172 memcpy(buffer, vaddr, len); 258 while (len > 0) {
173 else 259 offset = paddr - (paddr & PAGE_MASK);
174 memcpy(vaddr, buffer, len); 260 if (in_nmi) {
175 iounmap(vaddr); 261 raw_spin_lock(&ghes_ioremap_lock_nmi);
176 262 vaddr = ghes_ioremap_pfn_nmi(paddr >> PAGE_SHIFT);
177 return 0; 263 } else {
264 spin_lock_irqsave(&ghes_ioremap_lock_irq, flags);
265 vaddr = ghes_ioremap_pfn_irq(paddr >> PAGE_SHIFT);
266 }
267 trunk = PAGE_SIZE - offset;
268 trunk = min(trunk, len);
269 if (from_phys)
270 memcpy_fromio(buffer, vaddr + offset, trunk);
271 else
272 memcpy_toio(vaddr + offset, buffer, trunk);
273 len -= trunk;
274 paddr += trunk;
275 buffer += trunk;
276 if (in_nmi) {
277 ghes_iounmap_nmi(vaddr);
278 raw_spin_unlock(&ghes_ioremap_lock_nmi);
279 } else {
280 ghes_iounmap_irq(vaddr);
281 spin_unlock_irqrestore(&ghes_ioremap_lock_irq, flags);
282 }
283 }
178} 284}
179 285
180static int ghes_read_estatus(struct ghes *ghes, int silent) 286static int ghes_read_estatus(struct ghes *ghes, int silent)
@@ -195,10 +301,8 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
195 if (!buf_paddr) 301 if (!buf_paddr)
196 return -ENOENT; 302 return -ENOENT;
197 303
198 rc = ghes_copy_tofrom_phys(ghes->estatus, buf_paddr, 304 ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
199 sizeof(*ghes->estatus), 1); 305 sizeof(*ghes->estatus), 1);
200 if (rc)
201 return rc;
202 if (!ghes->estatus->block_status) 306 if (!ghes->estatus->block_status)
203 return -ENOENT; 307 return -ENOENT;
204 308
@@ -213,17 +317,15 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
213 goto err_read_block; 317 goto err_read_block;
214 if (apei_estatus_check_header(ghes->estatus)) 318 if (apei_estatus_check_header(ghes->estatus))
215 goto err_read_block; 319 goto err_read_block;
216 rc = ghes_copy_tofrom_phys(ghes->estatus + 1, 320 ghes_copy_tofrom_phys(ghes->estatus + 1,
217 buf_paddr + sizeof(*ghes->estatus), 321 buf_paddr + sizeof(*ghes->estatus),
218 len - sizeof(*ghes->estatus), 1); 322 len - sizeof(*ghes->estatus), 1);
219 if (rc)
220 return rc;
221 if (apei_estatus_check(ghes->estatus)) 323 if (apei_estatus_check(ghes->estatus))
222 goto err_read_block; 324 goto err_read_block;
223 rc = 0; 325 rc = 0;
224 326
225err_read_block: 327err_read_block:
226 if (rc && !silent) 328 if (rc && !silent && printk_ratelimit())
227 pr_warning(FW_WARN GHES_PFX 329 pr_warning(FW_WARN GHES_PFX
228 "Failed to read error status block!\n"); 330 "Failed to read error status block!\n");
229 return rc; 331 return rc;
@@ -293,6 +395,42 @@ out:
293 return 0; 395 return 0;
294} 396}
295 397
398static void ghes_add_timer(struct ghes *ghes)
399{
400 struct acpi_hest_generic *g = ghes->generic;
401 unsigned long expire;
402
403 if (!g->notify.poll_interval) {
404 pr_warning(FW_WARN GHES_PFX "Poll interval is 0 for generic hardware error source: %d, disabled.\n",
405 g->header.source_id);
406 return;
407 }
408 expire = jiffies + msecs_to_jiffies(g->notify.poll_interval);
409 ghes->timer.expires = round_jiffies_relative(expire);
410 add_timer(&ghes->timer);
411}
412
413static void ghes_poll_func(unsigned long data)
414{
415 struct ghes *ghes = (void *)data;
416
417 ghes_proc(ghes);
418 if (!(ghes->flags & GHES_EXITING))
419 ghes_add_timer(ghes);
420}
421
422static irqreturn_t ghes_irq_func(int irq, void *data)
423{
424 struct ghes *ghes = data;
425 int rc;
426
427 rc = ghes_proc(ghes);
428 if (rc)
429 return IRQ_NONE;
430
431 return IRQ_HANDLED;
432}
433
296static int ghes_notify_sci(struct notifier_block *this, 434static int ghes_notify_sci(struct notifier_block *this,
297 unsigned long event, void *data) 435 unsigned long event, void *data)
298{ 436{
@@ -309,10 +447,63 @@ static int ghes_notify_sci(struct notifier_block *this,
309 return ret; 447 return ret;
310} 448}
311 449
450static int ghes_notify_nmi(struct notifier_block *this,
451 unsigned long cmd, void *data)
452{
453 struct ghes *ghes, *ghes_global = NULL;
454 int sev, sev_global = -1;
455 int ret = NOTIFY_DONE;
456
457 if (cmd != DIE_NMI)
458 return ret;
459
460 raw_spin_lock(&ghes_nmi_lock);
461 list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
462 if (ghes_read_estatus(ghes, 1)) {
463 ghes_clear_estatus(ghes);
464 continue;
465 }
466 sev = ghes_severity(ghes->estatus->error_severity);
467 if (sev > sev_global) {
468 sev_global = sev;
469 ghes_global = ghes;
470 }
471 ret = NOTIFY_STOP;
472 }
473
474 if (ret == NOTIFY_DONE)
475 goto out;
476
477 if (sev_global >= GHES_SEV_PANIC) {
478 oops_begin();
479 ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global);
480 /* reboot to log the error! */
481 if (panic_timeout == 0)
482 panic_timeout = ghes_panic_timeout;
483 panic("Fatal hardware error!");
484 }
485
486 list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
487 if (!(ghes->flags & GHES_TO_CLEAR))
488 continue;
489 /* Do not print estatus because printk is not NMI safe */
490 ghes_do_proc(ghes);
491 ghes_clear_estatus(ghes);
492 }
493
494out:
495 raw_spin_unlock(&ghes_nmi_lock);
496 return ret;
497}
498
312static struct notifier_block ghes_notifier_sci = { 499static struct notifier_block ghes_notifier_sci = {
313 .notifier_call = ghes_notify_sci, 500 .notifier_call = ghes_notify_sci,
314}; 501};
315 502
503static struct notifier_block ghes_notifier_nmi = {
504 .notifier_call = ghes_notify_nmi,
505};
506
316static int __devinit ghes_probe(struct platform_device *ghes_dev) 507static int __devinit ghes_probe(struct platform_device *ghes_dev)
317{ 508{
318 struct acpi_hest_generic *generic; 509 struct acpi_hest_generic *generic;
@@ -323,18 +514,27 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
323 if (!generic->enabled) 514 if (!generic->enabled)
324 return -ENODEV; 515 return -ENODEV;
325 516
326 if (generic->error_block_length < 517 switch (generic->notify.type) {
327 sizeof(struct acpi_hest_generic_status)) { 518 case ACPI_HEST_NOTIFY_POLLED:
328 pr_warning(FW_BUG GHES_PFX 519 case ACPI_HEST_NOTIFY_EXTERNAL:
329"Invalid error block length: %u for generic hardware error source: %d\n", 520 case ACPI_HEST_NOTIFY_SCI:
330 generic->error_block_length, 521 case ACPI_HEST_NOTIFY_NMI:
522 break;
523 case ACPI_HEST_NOTIFY_LOCAL:
524 pr_warning(GHES_PFX "Generic hardware error source: %d notified via local interrupt is not supported!\n",
331 generic->header.source_id); 525 generic->header.source_id);
332 goto err; 526 goto err;
527 default:
528 pr_warning(FW_WARN GHES_PFX "Unknown notification type: %u for generic hardware error source: %d\n",
529 generic->notify.type, generic->header.source_id);
530 goto err;
333 } 531 }
334 if (generic->records_to_preallocate == 0) { 532
335 pr_warning(FW_BUG GHES_PFX 533 rc = -EIO;
336"Invalid records to preallocate: %u for generic hardware error source: %d\n", 534 if (generic->error_block_length <
337 generic->records_to_preallocate, 535 sizeof(struct acpi_hest_generic_status)) {
536 pr_warning(FW_BUG GHES_PFX "Invalid error block length: %u for generic hardware error source: %d\n",
537 generic->error_block_length,
338 generic->header.source_id); 538 generic->header.source_id);
339 goto err; 539 goto err;
340 } 540 }
@@ -344,38 +544,43 @@ static int __devinit ghes_probe(struct platform_device *ghes_dev)
344 ghes = NULL; 544 ghes = NULL;
345 goto err; 545 goto err;
346 } 546 }
347 if (generic->notify.type == ACPI_HEST_NOTIFY_SCI) { 547 switch (generic->notify.type) {
548 case ACPI_HEST_NOTIFY_POLLED:
549 ghes->timer.function = ghes_poll_func;
550 ghes->timer.data = (unsigned long)ghes;
551 init_timer_deferrable(&ghes->timer);
552 ghes_add_timer(ghes);
553 break;
554 case ACPI_HEST_NOTIFY_EXTERNAL:
555 /* External interrupt vector is GSI */
556 if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
557 pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
558 generic->header.source_id);
559 goto err;
560 }
561 if (request_irq(ghes->irq, ghes_irq_func,
562 0, "GHES IRQ", ghes)) {
563 pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
564 generic->header.source_id);
565 goto err;
566 }
567 break;
568 case ACPI_HEST_NOTIFY_SCI:
348 mutex_lock(&ghes_list_mutex); 569 mutex_lock(&ghes_list_mutex);
349 if (list_empty(&ghes_sci)) 570 if (list_empty(&ghes_sci))
350 register_acpi_hed_notifier(&ghes_notifier_sci); 571 register_acpi_hed_notifier(&ghes_notifier_sci);
351 list_add_rcu(&ghes->list, &ghes_sci); 572 list_add_rcu(&ghes->list, &ghes_sci);
352 mutex_unlock(&ghes_list_mutex); 573 mutex_unlock(&ghes_list_mutex);
353 } else { 574 break;
354 unsigned char *notify = NULL; 575 case ACPI_HEST_NOTIFY_NMI:
355 576 mutex_lock(&ghes_list_mutex);
356 switch (generic->notify.type) { 577 if (list_empty(&ghes_nmi))
357 case ACPI_HEST_NOTIFY_POLLED: 578 register_die_notifier(&ghes_notifier_nmi);
358 notify = "POLL"; 579 list_add_rcu(&ghes->list, &ghes_nmi);
359 break; 580 mutex_unlock(&ghes_list_mutex);
360 case ACPI_HEST_NOTIFY_EXTERNAL: 581 break;
361 case ACPI_HEST_NOTIFY_LOCAL: 582 default:
362 notify = "IRQ"; 583 BUG();
363 break;
364 case ACPI_HEST_NOTIFY_NMI:
365 notify = "NMI";
366 break;
367 }
368 if (notify) {
369 pr_warning(GHES_PFX
370"Generic hardware error source: %d notified via %s is not supported!\n",
371 generic->header.source_id, notify);
372 } else {
373 pr_warning(FW_WARN GHES_PFX
374"Unknown notification type: %u for generic hardware error source: %d\n",
375 generic->notify.type, generic->header.source_id);
376 }
377 rc = -ENODEV;
378 goto err;
379 } 584 }
380 platform_set_drvdata(ghes_dev, ghes); 585 platform_set_drvdata(ghes_dev, ghes);
381 586
@@ -396,7 +601,14 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
396 ghes = platform_get_drvdata(ghes_dev); 601 ghes = platform_get_drvdata(ghes_dev);
397 generic = ghes->generic; 602 generic = ghes->generic;
398 603
604 ghes->flags |= GHES_EXITING;
399 switch (generic->notify.type) { 605 switch (generic->notify.type) {
606 case ACPI_HEST_NOTIFY_POLLED:
607 del_timer_sync(&ghes->timer);
608 break;
609 case ACPI_HEST_NOTIFY_EXTERNAL:
610 free_irq(ghes->irq, ghes);
611 break;
400 case ACPI_HEST_NOTIFY_SCI: 612 case ACPI_HEST_NOTIFY_SCI:
401 mutex_lock(&ghes_list_mutex); 613 mutex_lock(&ghes_list_mutex);
402 list_del_rcu(&ghes->list); 614 list_del_rcu(&ghes->list);
@@ -404,12 +616,23 @@ static int __devexit ghes_remove(struct platform_device *ghes_dev)
404 unregister_acpi_hed_notifier(&ghes_notifier_sci); 616 unregister_acpi_hed_notifier(&ghes_notifier_sci);
405 mutex_unlock(&ghes_list_mutex); 617 mutex_unlock(&ghes_list_mutex);
406 break; 618 break;
619 case ACPI_HEST_NOTIFY_NMI:
620 mutex_lock(&ghes_list_mutex);
621 list_del_rcu(&ghes->list);
622 if (list_empty(&ghes_nmi))
623 unregister_die_notifier(&ghes_notifier_nmi);
624 mutex_unlock(&ghes_list_mutex);
625 /*
626 * To synchronize with NMI handler, ghes can only be
627 * freed after NMI handler finishes.
628 */
629 synchronize_rcu();
630 break;
407 default: 631 default:
408 BUG(); 632 BUG();
409 break; 633 break;
410 } 634 }
411 635
412 synchronize_rcu();
413 ghes_fini(ghes); 636 ghes_fini(ghes);
414 kfree(ghes); 637 kfree(ghes);
415 638
@@ -429,6 +652,8 @@ static struct platform_driver ghes_platform_driver = {
429 652
430static int __init ghes_init(void) 653static int __init ghes_init(void)
431{ 654{
655 int rc;
656
432 if (acpi_disabled) 657 if (acpi_disabled)
433 return -ENODEV; 658 return -ENODEV;
434 659
@@ -437,12 +662,25 @@ static int __init ghes_init(void)
437 return -EINVAL; 662 return -EINVAL;
438 } 663 }
439 664
440 return platform_driver_register(&ghes_platform_driver); 665 rc = ghes_ioremap_init();
666 if (rc)
667 goto err;
668
669 rc = platform_driver_register(&ghes_platform_driver);
670 if (rc)
671 goto err_ioremap_exit;
672
673 return 0;
674err_ioremap_exit:
675 ghes_ioremap_exit();
676err:
677 return rc;
441} 678}
442 679
443static void __exit ghes_exit(void) 680static void __exit ghes_exit(void)
444{ 681{
445 platform_driver_unregister(&ghes_platform_driver); 682 platform_driver_unregister(&ghes_platform_driver);
683 ghes_ioremap_exit();
446} 684}
447 685
448module_init(ghes_init); 686module_init(ghes_init);