aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei/ghes.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei/ghes.c')
-rw-r--r--drivers/acpi/apei/ghes.c102
1 files changed, 83 insertions, 19 deletions
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)