aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/apei-base.c150
-rw-r--r--drivers/acpi/apei/apei-internal.h6
-rw-r--r--drivers/acpi/apei/einj.c66
-rw-r--r--drivers/acpi/apei/erst.c5
-rw-r--r--drivers/acpi/apei/ghes.c102
-rw-r--r--drivers/acpi/apei/hest.c5
6 files changed, 288 insertions, 46 deletions
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 61540360d5ce..e45350cb6ac8 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -34,13 +34,13 @@
34#include <linux/module.h> 34#include <linux/module.h>
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/acpi.h> 36#include <linux/acpi.h>
37#include <linux/acpi_io.h>
37#include <linux/slab.h> 38#include <linux/slab.h>
38#include <linux/io.h> 39#include <linux/io.h>
39#include <linux/kref.h> 40#include <linux/kref.h>
40#include <linux/rculist.h> 41#include <linux/rculist.h>
41#include <linux/interrupt.h> 42#include <linux/interrupt.h>
42#include <linux/debugfs.h> 43#include <linux/debugfs.h>
43#include <acpi/atomicio.h>
44 44
45#include "apei-internal.h" 45#include "apei-internal.h"
46 46
@@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val)
70{ 70{
71 int rc; 71 int rc;
72 72
73 rc = acpi_atomic_read(val, &entry->register_region); 73 rc = apei_read(val, &entry->register_region);
74 if (rc) 74 if (rc)
75 return rc; 75 return rc;
76 *val >>= entry->register_region.bit_offset; 76 *val >>= entry->register_region.bit_offset;
@@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val)
116 val <<= entry->register_region.bit_offset; 116 val <<= entry->register_region.bit_offset;
117 if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { 117 if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) {
118 u64 valr = 0; 118 u64 valr = 0;
119 rc = acpi_atomic_read(&valr, &entry->register_region); 119 rc = apei_read(&valr, &entry->register_region);
120 if (rc) 120 if (rc)
121 return rc; 121 return rc;
122 valr &= ~(entry->mask << entry->register_region.bit_offset); 122 valr &= ~(entry->mask << entry->register_region.bit_offset);
123 val |= valr; 123 val |= valr;
124 } 124 }
125 rc = acpi_atomic_write(val, &entry->register_region); 125 rc = apei_write(val, &entry->register_region);
126 126
127 return rc; 127 return rc;
128} 128}
@@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx,
243 u8 ins = entry->instruction; 243 u8 ins = entry->instruction;
244 244
245 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 245 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
246 return acpi_pre_map_gar(&entry->register_region); 246 return acpi_os_map_generic_address(&entry->register_region);
247 247
248 return 0; 248 return 0;
249} 249}
@@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx,
276 u8 ins = entry->instruction; 276 u8 ins = entry->instruction;
277 277
278 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) 278 if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER)
279 acpi_post_unmap_gar(&entry->register_region); 279 acpi_os_unmap_generic_address(&entry->register_region);
280 280
281 return 0; 281 return 0;
282} 282}
@@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1,
421 return 0; 421 return 0;
422} 422}
423 423
424int apei_resources_add(struct apei_resources *resources,
425 unsigned long start, unsigned long size,
426 bool iomem)
427{
428 if (iomem)
429 return apei_res_add(&resources->iomem, start, size);
430 else
431 return apei_res_add(&resources->ioport, start, size);
432}
433EXPORT_SYMBOL_GPL(apei_resources_add);
434
424/* 435/*
425 * EINJ has two groups of GARs (EINJ table entry and trigger table 436 * EINJ has two groups of GARs (EINJ table entry and trigger table
426 * entry), so common resources are subtracted from the trigger table 437 * entry), so common resources are subtracted from the trigger table
@@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1,
438} 449}
439EXPORT_SYMBOL_GPL(apei_resources_sub); 450EXPORT_SYMBOL_GPL(apei_resources_sub);
440 451
452static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
453{
454 struct apei_resources *resources = data;
455 return apei_res_add(&resources->iomem, start, size);
456}
457
458static int apei_get_nvs_resources(struct apei_resources *resources)
459{
460 return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
461}
462
441/* 463/*
442 * IO memory/port rersource management mechanism is used to check 464 * IO memory/port resource management mechanism is used to check
443 * whether memory/port area used by GARs conflicts with normal memory 465 * whether memory/port area used by GARs conflicts with normal memory
444 * or IO memory/port of devices. 466 * or IO memory/port of devices.
445 */ 467 */
@@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources,
448{ 470{
449 struct apei_res *res, *res_bak = NULL; 471 struct apei_res *res, *res_bak = NULL;
450 struct resource *r; 472 struct resource *r;
473 struct apei_resources nvs_resources;
451 int rc; 474 int rc;
452 475
453 rc = apei_resources_sub(resources, &apei_resources_all); 476 rc = apei_resources_sub(resources, &apei_resources_all);
454 if (rc) 477 if (rc)
455 return rc; 478 return rc;
456 479
480 /*
481 * Some firmware uses ACPI NVS region, that has been marked as
482 * busy, so exclude it from APEI resources to avoid false
483 * conflict.
484 */
485 apei_resources_init(&nvs_resources);
486 rc = apei_get_nvs_resources(&nvs_resources);
487 if (rc)
488 goto res_fini;
489 rc = apei_resources_sub(resources, &nvs_resources);
490 if (rc)
491 goto res_fini;
492
457 rc = -EINVAL; 493 rc = -EINVAL;
458 list_for_each_entry(res, &resources->iomem, list) { 494 list_for_each_entry(res, &resources->iomem, list) {
459 r = request_mem_region(res->start, res->end - res->start, 495 r = request_mem_region(res->start, res->end - res->start,
460 desc); 496 desc);
461 if (!r) { 497 if (!r) {
462 pr_err(APEI_PFX 498 pr_err(APEI_PFX
463 "Can not request iomem region <%016llx-%016llx> for GARs.\n", 499 "Can not request [mem %#010llx-%#010llx] for %s registers\n",
464 (unsigned long long)res->start, 500 (unsigned long long)res->start,
465 (unsigned long long)res->end); 501 (unsigned long long)res->end - 1, desc);
466 res_bak = res; 502 res_bak = res;
467 goto err_unmap_iomem; 503 goto err_unmap_iomem;
468 } 504 }
@@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources,
472 r = request_region(res->start, res->end - res->start, desc); 508 r = request_region(res->start, res->end - res->start, desc);
473 if (!r) { 509 if (!r) {
474 pr_err(APEI_PFX 510 pr_err(APEI_PFX
475 "Can not request ioport region <%016llx-%016llx> for GARs.\n", 511 "Can not request [io %#06llx-%#06llx] for %s registers\n",
476 (unsigned long long)res->start, 512 (unsigned long long)res->start,
477 (unsigned long long)res->end); 513 (unsigned long long)res->end - 1, desc);
478 res_bak = res; 514 res_bak = res;
479 goto err_unmap_ioport; 515 goto err_unmap_ioport;
480 } 516 }
@@ -500,6 +536,8 @@ err_unmap_iomem:
500 break; 536 break;
501 release_mem_region(res->start, res->end - res->start); 537 release_mem_region(res->start, res->end - res->start);
502 } 538 }
539res_fini:
540 apei_resources_fini(&nvs_resources);
503 return rc; 541 return rc;
504} 542}
505EXPORT_SYMBOL_GPL(apei_resources_request); 543EXPORT_SYMBOL_GPL(apei_resources_request);
@@ -553,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr)
553 return 0; 591 return 0;
554} 592}
555 593
594/* read GAR in interrupt (including NMI) or process context */
595int apei_read(u64 *val, struct acpi_generic_address *reg)
596{
597 int rc;
598 u64 address;
599 u32 tmp, width = reg->bit_width;
600 acpi_status status;
601
602 rc = apei_check_gar(reg, &address);
603 if (rc)
604 return rc;
605
606 if (width == 64)
607 width = 32; /* Break into two 32-bit transfers */
608
609 *val = 0;
610 switch(reg->space_id) {
611 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
612 status = acpi_os_read_memory((acpi_physical_address)
613 address, &tmp, width);
614 if (ACPI_FAILURE(status))
615 return -EIO;
616 *val = tmp;
617
618 if (reg->bit_width == 64) {
619 /* Read the top 32 bits */
620 status = acpi_os_read_memory((acpi_physical_address)
621 (address + 4), &tmp, 32);
622 if (ACPI_FAILURE(status))
623 return -EIO;
624 *val |= ((u64)tmp << 32);
625 }
626 break;
627 case ACPI_ADR_SPACE_SYSTEM_IO:
628 status = acpi_os_read_port(address, (u32 *)val, reg->bit_width);
629 if (ACPI_FAILURE(status))
630 return -EIO;
631 break;
632 default:
633 return -EINVAL;
634 }
635
636 return 0;
637}
638EXPORT_SYMBOL_GPL(apei_read);
639
640/* write GAR in interrupt (including NMI) or process context */
641int apei_write(u64 val, struct acpi_generic_address *reg)
642{
643 int rc;
644 u64 address;
645 u32 width = reg->bit_width;
646 acpi_status status;
647
648 rc = apei_check_gar(reg, &address);
649 if (rc)
650 return rc;
651
652 if (width == 64)
653 width = 32; /* Break into two 32-bit transfers */
654
655 switch (reg->space_id) {
656 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
657 status = acpi_os_write_memory((acpi_physical_address)
658 address, ACPI_LODWORD(val),
659 width);
660 if (ACPI_FAILURE(status))
661 return -EIO;
662
663 if (reg->bit_width == 64) {
664 status = acpi_os_write_memory((acpi_physical_address)
665 (address + 4),
666 ACPI_HIDWORD(val), 32);
667 if (ACPI_FAILURE(status))
668 return -EIO;
669 }
670 break;
671 case ACPI_ADR_SPACE_SYSTEM_IO:
672 status = acpi_os_write_port(address, val, reg->bit_width);
673 if (ACPI_FAILURE(status))
674 return -EIO;
675 break;
676 default:
677 return -EINVAL;
678 }
679
680 return 0;
681}
682EXPORT_SYMBOL_GPL(apei_write);
683
556static int collect_res_callback(struct apei_exec_context *ctx, 684static int collect_res_callback(struct apei_exec_context *ctx,
557 struct acpi_whea_header *entry, 685 struct acpi_whea_header *entry,
558 void *data) 686 void *data)
diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h
index f57050e7a5e7..cca240a33038 100644
--- a/drivers/acpi/apei/apei-internal.h
+++ b/drivers/acpi/apei/apei-internal.h
@@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio
68/* IP has been set in instruction function */ 68/* IP has been set in instruction function */
69#define APEI_EXEC_SET_IP 1 69#define APEI_EXEC_SET_IP 1
70 70
71int apei_read(u64 *val, struct acpi_generic_address *reg);
72int apei_write(u64 val, struct acpi_generic_address *reg);
73
71int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); 74int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val);
72int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); 75int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val);
73int apei_exec_read_register(struct apei_exec_context *ctx, 76int apei_exec_read_register(struct apei_exec_context *ctx,
@@ -95,6 +98,9 @@ static inline void apei_resources_init(struct apei_resources *resources)
95} 98}
96 99
97void apei_resources_fini(struct apei_resources *resources); 100void apei_resources_fini(struct apei_resources *resources);
101int apei_resources_add(struct apei_resources *resources,
102 unsigned long start, unsigned long size,
103 bool iomem);
98int apei_resources_sub(struct apei_resources *resources1, 104int apei_resources_sub(struct apei_resources *resources1,
99 struct apei_resources *resources2); 105 struct apei_resources *resources2);
100int apei_resources_request(struct apei_resources *resources, 106int apei_resources_request(struct apei_resources *resources,
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 31546fd21029..5b898d4dda99 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -286,8 +286,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab)
286 return 0; 286 return 0;
287} 287}
288 288
289static struct acpi_generic_address *einj_get_trigger_parameter_region(
290 struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2)
291{
292 int i;
293 struct acpi_whea_header *entry;
294
295 entry = (struct acpi_whea_header *)
296 ((char *)trigger_tab + sizeof(struct acpi_einj_trigger));
297 for (i = 0; i < trigger_tab->entry_count; i++) {
298 if (entry->action == ACPI_EINJ_TRIGGER_ERROR &&
299 entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE &&
300 entry->register_region.space_id ==
301 ACPI_ADR_SPACE_SYSTEM_MEMORY &&
302 (entry->register_region.address & param2) == (param1 & param2))
303 return &entry->register_region;
304 entry++;
305 }
306
307 return NULL;
308}
289/* Execute instructions in trigger error action table */ 309/* Execute instructions in trigger error action table */
290static int __einj_error_trigger(u64 trigger_paddr) 310static int __einj_error_trigger(u64 trigger_paddr, u32 type,
311 u64 param1, u64 param2)
291{ 312{
292 struct acpi_einj_trigger *trigger_tab = NULL; 313 struct acpi_einj_trigger *trigger_tab = NULL;
293 struct apei_exec_context trigger_ctx; 314 struct apei_exec_context trigger_ctx;
@@ -296,14 +317,16 @@ static int __einj_error_trigger(u64 trigger_paddr)
296 struct resource *r; 317 struct resource *r;
297 u32 table_size; 318 u32 table_size;
298 int rc = -EIO; 319 int rc = -EIO;
320 struct acpi_generic_address *trigger_param_region = NULL;
299 321
300 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), 322 r = request_mem_region(trigger_paddr, sizeof(*trigger_tab),
301 "APEI EINJ Trigger Table"); 323 "APEI EINJ Trigger Table");
302 if (!r) { 324 if (!r) {
303 pr_err(EINJ_PFX 325 pr_err(EINJ_PFX
304 "Can not request iomem region <%016llx-%016llx> for Trigger table.\n", 326 "Can not request [mem %#010llx-%#010llx] for Trigger table\n",
305 (unsigned long long)trigger_paddr, 327 (unsigned long long)trigger_paddr,
306 (unsigned long long)trigger_paddr+sizeof(*trigger_tab)); 328 (unsigned long long)trigger_paddr +
329 sizeof(*trigger_tab) - 1);
307 goto out; 330 goto out;
308 } 331 }
309 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); 332 trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab));
@@ -324,9 +347,9 @@ static int __einj_error_trigger(u64 trigger_paddr)
324 "APEI EINJ Trigger Table"); 347 "APEI EINJ Trigger Table");
325 if (!r) { 348 if (!r) {
326 pr_err(EINJ_PFX 349 pr_err(EINJ_PFX
327"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n", 350"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n",
328 (unsigned long long)trigger_paddr+sizeof(*trigger_tab), 351 (unsigned long long)trigger_paddr + sizeof(*trigger_tab),
329 (unsigned long long)trigger_paddr + table_size); 352 (unsigned long long)trigger_paddr + table_size - 1);
330 goto out_rel_header; 353 goto out_rel_header;
331 } 354 }
332 iounmap(trigger_tab); 355 iounmap(trigger_tab);
@@ -347,6 +370,30 @@ static int __einj_error_trigger(u64 trigger_paddr)
347 rc = apei_resources_sub(&trigger_resources, &einj_resources); 370 rc = apei_resources_sub(&trigger_resources, &einj_resources);
348 if (rc) 371 if (rc)
349 goto out_fini; 372 goto out_fini;
373 /*
374 * Some firmware will access target address specified in
375 * param1 to trigger the error when injecting memory error.
376 * This will cause resource conflict with regular memory. So
377 * remove it from trigger table resources.
378 */
379 if (param_extension && (type & 0x0038) && param2) {
380 struct apei_resources addr_resources;
381 apei_resources_init(&addr_resources);
382 trigger_param_region = einj_get_trigger_parameter_region(
383 trigger_tab, param1, param2);
384 if (trigger_param_region) {
385 rc = apei_resources_add(&addr_resources,
386 trigger_param_region->address,
387 trigger_param_region->bit_width/8, true);
388 if (rc)
389 goto out_fini;
390 rc = apei_resources_sub(&trigger_resources,
391 &addr_resources);
392 }
393 apei_resources_fini(&addr_resources);
394 if (rc)
395 goto out_fini;
396 }
350 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); 397 rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger");
351 if (rc) 398 if (rc)
352 goto out_fini; 399 goto out_fini;
@@ -460,7 +507,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2)
460 if (rc) 507 if (rc)
461 return rc; 508 return rc;
462 trigger_paddr = apei_exec_ctx_get_output(&ctx); 509 trigger_paddr = apei_exec_ctx_get_output(&ctx);
463 rc = __einj_error_trigger(trigger_paddr); 510 rc = __einj_error_trigger(trigger_paddr, type, param1, param2);
464 if (rc) 511 if (rc)
465 return rc; 512 return rc;
466 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); 513 rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION);
@@ -610,10 +657,9 @@ static int __init einj_init(void)
610 657
611 status = acpi_get_table(ACPI_SIG_EINJ, 0, 658 status = acpi_get_table(ACPI_SIG_EINJ, 0,
612 (struct acpi_table_header **)&einj_tab); 659 (struct acpi_table_header **)&einj_tab);
613 if (status == AE_NOT_FOUND) { 660 if (status == AE_NOT_FOUND)
614 pr_info(EINJ_PFX "Table is not found!\n");
615 return -ENODEV; 661 return -ENODEV;
616 } else if (ACPI_FAILURE(status)) { 662 else if (ACPI_FAILURE(status)) {
617 const char *msg = acpi_format_exception(status); 663 const char *msg = acpi_format_exception(status);
618 pr_err(EINJ_PFX "Failed to get table, %s\n", msg); 664 pr_err(EINJ_PFX "Failed to get table, %s\n", msg);
619 return -EINVAL; 665 return -EINVAL;
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 631b9477b99c..8e8d786c5d23 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -1125,10 +1125,9 @@ static int __init erst_init(void)
1125 1125
1126 status = acpi_get_table(ACPI_SIG_ERST, 0, 1126 status = acpi_get_table(ACPI_SIG_ERST, 0,
1127 (struct acpi_table_header **)&erst_tab); 1127 (struct acpi_table_header **)&erst_tab);
1128 if (status == AE_NOT_FOUND) { 1128 if (status == AE_NOT_FOUND)
1129 pr_info(ERST_PFX "Table is not found!\n");
1130 goto err; 1129 goto err;
1131 } else if (ACPI_FAILURE(status)) { 1130 else if (ACPI_FAILURE(status)) {
1132 const char *msg = acpi_format_exception(status); 1131 const char *msg = acpi_format_exception(status);
1133 pr_err(ERST_PFX "Failed to get table, %s\n", msg); 1132 pr_err(ERST_PFX "Failed to get table, %s\n", msg);
1134 rc = -EINVAL; 1133 rc = -EINVAL;
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index b8e08cb67a18..b3207e16670e 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -33,6 +33,7 @@
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/init.h> 34#include <linux/init.h>
35#include <linux/acpi.h> 35#include <linux/acpi.h>
36#include <linux/acpi_io.h>
36#include <linux/io.h> 37#include <linux/io.h>
37#include <linux/interrupt.h> 38#include <linux/interrupt.h>
38#include <linux/timer.h> 39#include <linux/timer.h>
@@ -45,8 +46,9 @@
45#include <linux/irq_work.h> 46#include <linux/irq_work.h>
46#include <linux/llist.h> 47#include <linux/llist.h>
47#include <linux/genalloc.h> 48#include <linux/genalloc.h>
49#include <linux/pci.h>
50#include <linux/aer.h>
48#include <acpi/apei.h> 51#include <acpi/apei.h>
49#include <acpi/atomicio.h>
50#include <acpi/hed.h> 52#include <acpi/hed.h>
51#include <asm/mce.h> 53#include <asm/mce.h>
52#include <asm/tlbflush.h> 54#include <asm/tlbflush.h>
@@ -299,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
299 if (!ghes) 301 if (!ghes)
300 return ERR_PTR(-ENOMEM); 302 return ERR_PTR(-ENOMEM);
301 ghes->generic = generic; 303 ghes->generic = generic;
302 rc = acpi_pre_map_gar(&generic->error_status_address); 304 rc = acpi_os_map_generic_address(&generic->error_status_address);
303 if (rc) 305 if (rc)
304 goto err_free; 306 goto err_free;
305 error_block_length = generic->error_block_length; 307 error_block_length = generic->error_block_length;
@@ -319,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic)
319 return ghes; 321 return ghes;
320 322
321err_unmap: 323err_unmap:
322 acpi_post_unmap_gar(&generic->error_status_address); 324 acpi_os_unmap_generic_address(&generic->error_status_address);
323err_free: 325err_free:
324 kfree(ghes); 326 kfree(ghes);
325 return ERR_PTR(rc); 327 return ERR_PTR(rc);
@@ -328,7 +330,7 @@ err_free:
328static void ghes_fini(struct ghes *ghes) 330static void ghes_fini(struct ghes *ghes)
329{ 331{
330 kfree(ghes->estatus); 332 kfree(ghes->estatus);
331 acpi_post_unmap_gar(&ghes->generic->error_status_address); 333 acpi_os_unmap_generic_address(&ghes->generic->error_status_address);
332} 334}
333 335
334enum { 336enum {
@@ -399,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent)
399 u32 len; 401 u32 len;
400 int rc; 402 int rc;
401 403
402 rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); 404 rc = apei_read(&buf_paddr, &g->error_status_address);
403 if (rc) { 405 if (rc) {
404 if (!silent && printk_ratelimit()) 406 if (!silent && printk_ratelimit())
405 pr_warning(FW_WARN GHES_PFX 407 pr_warning(FW_WARN GHES_PFX
@@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
476 } 478 }
477#endif 479#endif
478 } 480 }
481#ifdef CONFIG_ACPI_APEI_PCIEAER
482 else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type,
483 CPER_SEC_PCIE)) {
484 struct cper_sec_pcie *pcie_err;
485 pcie_err = (struct cper_sec_pcie *)(gdata+1);
486 if (sev == GHES_SEV_RECOVERABLE &&
487 sec_sev == GHES_SEV_RECOVERABLE &&
488 pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
489 pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
490 unsigned int devfn;
491 int aer_severity;
492 devfn = PCI_DEVFN(pcie_err->device_id.device,
493 pcie_err->device_id.function);
494 aer_severity = cper_severity_to_aer(sev);
495 aer_recover_queue(pcie_err->device_id.segment,
496 pcie_err->device_id.bus,
497 devfn, aer_severity);
498 }
499
500 }
501#endif
479 } 502 }
480} 503}
481 504
@@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx,
483 const struct acpi_hest_generic *generic, 506 const struct acpi_hest_generic *generic,
484 const struct acpi_hest_generic_status *estatus) 507 const struct acpi_hest_generic_status *estatus)
485{ 508{
509 static atomic_t seqno;
510 unsigned int curr_seqno;
511 char pfx_seq[64];
512
486 if (pfx == NULL) { 513 if (pfx == NULL) {
487 if (ghes_severity(estatus->error_severity) <= 514 if (ghes_severity(estatus->error_severity) <=
488 GHES_SEV_CORRECTED) 515 GHES_SEV_CORRECTED)
489 pfx = KERN_WARNING HW_ERR; 516 pfx = KERN_WARNING;
490 else 517 else
491 pfx = KERN_ERR HW_ERR; 518 pfx = KERN_ERR;
492 } 519 }
520 curr_seqno = atomic_inc_return(&seqno);
521 snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno);
493 printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", 522 printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n",
494 pfx, generic->header.source_id); 523 pfx_seq, generic->header.source_id);
495 apei_estatus_print(pfx, estatus); 524 apei_estatus_print(pfx_seq, estatus);
496} 525}
497 526
498static int ghes_print_estatus(const char *pfx, 527static int ghes_print_estatus(const char *pfx,
@@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this,
711 return ret; 740 return ret;
712} 741}
713 742
743static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
744{
745 struct llist_node *next, *tail = NULL;
746
747 while (llnode) {
748 next = llnode->next;
749 llnode->next = tail;
750 tail = llnode;
751 llnode = next;
752 }
753
754 return tail;
755}
756
714static void ghes_proc_in_irq(struct irq_work *irq_work) 757static void ghes_proc_in_irq(struct irq_work *irq_work)
715{ 758{
716 struct llist_node *llnode, *next, *tail = NULL; 759 struct llist_node *llnode, *next;
717 struct ghes_estatus_node *estatus_node; 760 struct ghes_estatus_node *estatus_node;
718 struct acpi_hest_generic *generic; 761 struct acpi_hest_generic *generic;
719 struct acpi_hest_generic_status *estatus; 762 struct acpi_hest_generic_status *estatus;
720 u32 len, node_len; 763 u32 len, node_len;
721 764
765 llnode = llist_del_all(&ghes_estatus_llist);
722 /* 766 /*
723 * Because the time order of estatus in list is reversed, 767 * Because the time order of estatus in list is reversed,
724 * revert it back to proper order. 768 * revert it back to proper order.
725 */ 769 */
726 llnode = llist_del_all(&ghes_estatus_llist); 770 llnode = llist_nodes_reverse(llnode);
727 while (llnode) {
728 next = llnode->next;
729 llnode->next = tail;
730 tail = llnode;
731 llnode = next;
732 }
733 llnode = tail;
734 while (llnode) { 771 while (llnode) {
735 next = llnode->next; 772 next = llnode->next;
736 estatus_node = llist_entry(llnode, struct ghes_estatus_node, 773 estatus_node = llist_entry(llnode, struct ghes_estatus_node,
@@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
750 } 787 }
751} 788}
752 789
790static void ghes_print_queued_estatus(void)
791{
792 struct llist_node *llnode;
793 struct ghes_estatus_node *estatus_node;
794 struct acpi_hest_generic *generic;
795 struct acpi_hest_generic_status *estatus;
796 u32 len, node_len;
797
798 llnode = llist_del_all(&ghes_estatus_llist);
799 /*
800 * Because the time order of estatus in list is reversed,
801 * revert it back to proper order.
802 */
803 llnode = llist_nodes_reverse(llnode);
804 while (llnode) {
805 estatus_node = llist_entry(llnode, struct ghes_estatus_node,
806 llnode);
807 estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
808 len = apei_estatus_len(estatus);
809 node_len = GHES_ESTATUS_NODE_LEN(len);
810 generic = estatus_node->generic;
811 ghes_print_estatus(NULL, generic, estatus);
812 llnode = llnode->next;
813 }
814}
815
753static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) 816static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
754{ 817{
755 struct ghes *ghes, *ghes_global = NULL; 818 struct ghes *ghes, *ghes_global = NULL;
@@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
775 838
776 if (sev_global >= GHES_SEV_PANIC) { 839 if (sev_global >= GHES_SEV_PANIC) {
777 oops_begin(); 840 oops_begin();
778 __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, 841 ghes_print_queued_estatus();
842 __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
779 ghes_global->estatus); 843 ghes_global->estatus);
780 /* reboot to log the error! */ 844 /* reboot to log the error! */
781 if (panic_timeout == 0) 845 if (panic_timeout == 0)
diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c
index 05fee06f4d6e..f709269d4932 100644
--- a/drivers/acpi/apei/hest.c
+++ b/drivers/acpi/apei/hest.c
@@ -221,10 +221,9 @@ void __init acpi_hest_init(void)
221 221
222 status = acpi_get_table(ACPI_SIG_HEST, 0, 222 status = acpi_get_table(ACPI_SIG_HEST, 0,
223 (struct acpi_table_header **)&hest_tab); 223 (struct acpi_table_header **)&hest_tab);
224 if (status == AE_NOT_FOUND) { 224 if (status == AE_NOT_FOUND)
225 pr_info(HEST_PFX "Table not found.\n");
226 goto err; 225 goto err;
227 } else if (ACPI_FAILURE(status)) { 226 else if (ACPI_FAILURE(status)) {
228 const char *msg = acpi_format_exception(status); 227 const char *msg = acpi_format_exception(status);
229 pr_err(HEST_PFX "Failed to get table, %s\n", msg); 228 pr_err(HEST_PFX "Failed to get table, %s\n", msg);
230 rc = -EINVAL; 229 rc = -EINVAL;