aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/acpi/boot.c1
-rw-r--r--arch/x86/kernel/dumpstack.c1
-rw-r--r--drivers/acpi/apei/ghes.c406
-rw-r--r--kernel/panic.c1
-rw-r--r--lib/ioremap.c2
-rw-r--r--mm/vmalloc.c1
6 files changed, 328 insertions, 84 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 71232b941b6c..c2d0baa48d8c 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -504,6 +504,7 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
504 504
505 return 0; 505 return 0;
506} 506}
507EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
507 508
508int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi) 509int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
509{ 510{
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 6e8752c1bd52..d34cf80ec402 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -240,6 +240,7 @@ unsigned __kprobes long oops_begin(void)
240 bust_spinlocks(1); 240 bust_spinlocks(1);
241 return flags; 241 return flags;
242} 242}
243EXPORT_SYMBOL_GPL(oops_begin);
243 244
244void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) 245void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr)
245{ 246{
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);
diff --git a/kernel/panic.c b/kernel/panic.c
index 4c13b1a88ebb..991bb87a1704 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -34,6 +34,7 @@ static int pause_on_oops_flag;
34static DEFINE_SPINLOCK(pause_on_oops_lock); 34static DEFINE_SPINLOCK(pause_on_oops_lock);
35 35
36int panic_timeout; 36int panic_timeout;
37EXPORT_SYMBOL_GPL(panic_timeout);
37 38
38ATOMIC_NOTIFIER_HEAD(panic_notifier_list); 39ATOMIC_NOTIFIER_HEAD(panic_notifier_list);
39 40
diff --git a/lib/ioremap.c b/lib/ioremap.c
index 5730ecd3eb66..da4e2ad74b68 100644
--- a/lib/ioremap.c
+++ b/lib/ioremap.c
@@ -9,6 +9,7 @@
9#include <linux/mm.h> 9#include <linux/mm.h>
10#include <linux/sched.h> 10#include <linux/sched.h>
11#include <linux/io.h> 11#include <linux/io.h>
12#include <linux/module.h>
12#include <asm/cacheflush.h> 13#include <asm/cacheflush.h>
13#include <asm/pgtable.h> 14#include <asm/pgtable.h>
14 15
@@ -90,3 +91,4 @@ int ioremap_page_range(unsigned long addr,
90 91
91 return err; 92 return err;
92} 93}
94EXPORT_SYMBOL_GPL(ioremap_page_range);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index eb5cc7d00c5a..816f074fb4e1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1175,6 +1175,7 @@ void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
1175{ 1175{
1176 vunmap_page_range(addr, addr + size); 1176 vunmap_page_range(addr, addr + size);
1177} 1177}
1178EXPORT_SYMBOL_GPL(unmap_kernel_range_noflush);
1178 1179
1179/** 1180/**
1180 * unmap_kernel_range - unmap kernel VM area and flush cache and TLB 1181 * unmap_kernel_range - unmap kernel VM area and flush cache and TLB