aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/apei/ghes.c24
-rw-r--r--include/acpi/ghes.h27
2 files changed, 46 insertions, 5 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 6d0e146e0fee..d668a8ae602b 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -409,7 +409,8 @@ static void ghes_clear_estatus(struct ghes *ghes)
409 ghes->flags &= ~GHES_TO_CLEAR; 409 ghes->flags &= ~GHES_TO_CLEAR;
410} 410}
411 411
412static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) 412static void ghes_do_proc(struct ghes *ghes,
413 const struct acpi_hest_generic_status *estatus)
413{ 414{
414 int sev, sec_sev; 415 int sev, sec_sev;
415 struct acpi_hest_generic_data *gdata; 416 struct acpi_hest_generic_data *gdata;
@@ -421,6 +422,8 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus)
421 CPER_SEC_PLATFORM_MEM)) { 422 CPER_SEC_PLATFORM_MEM)) {
422 struct cper_sec_mem_err *mem_err; 423 struct cper_sec_mem_err *mem_err;
423 mem_err = (struct cper_sec_mem_err *)(gdata+1); 424 mem_err = (struct cper_sec_mem_err *)(gdata+1);
425 ghes_edac_report_mem_error(ghes, sev, mem_err);
426
424#ifdef CONFIG_X86_MCE 427#ifdef CONFIG_X86_MCE
425 apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED, 428 apei_mce_report_mem_error(sev == GHES_SEV_CORRECTED,
426 mem_err); 429 mem_err);
@@ -639,7 +642,7 @@ static int ghes_proc(struct ghes *ghes)
639 if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus)) 642 if (ghes_print_estatus(NULL, ghes->generic, ghes->estatus))
640 ghes_estatus_cache_add(ghes->generic, ghes->estatus); 643 ghes_estatus_cache_add(ghes->generic, ghes->estatus);
641 } 644 }
642 ghes_do_proc(ghes->estatus); 645 ghes_do_proc(ghes, ghes->estatus);
643out: 646out:
644 ghes_clear_estatus(ghes); 647 ghes_clear_estatus(ghes);
645 return 0; 648 return 0;
@@ -732,7 +735,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
732 estatus = GHES_ESTATUS_FROM_NODE(estatus_node); 735 estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
733 len = apei_estatus_len(estatus); 736 len = apei_estatus_len(estatus);
734 node_len = GHES_ESTATUS_NODE_LEN(len); 737 node_len = GHES_ESTATUS_NODE_LEN(len);
735 ghes_do_proc(estatus); 738 ghes_do_proc(estatus_node->ghes, estatus);
736 if (!ghes_estatus_cached(estatus)) { 739 if (!ghes_estatus_cached(estatus)) {
737 generic = estatus_node->generic; 740 generic = estatus_node->generic;
738 if (ghes_print_estatus(NULL, generic, estatus)) 741 if (ghes_print_estatus(NULL, generic, estatus))
@@ -821,6 +824,7 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
821 estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, 824 estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
822 node_len); 825 node_len);
823 if (estatus_node) { 826 if (estatus_node) {
827 estatus_node->ghes = ghes;
824 estatus_node->generic = ghes->generic; 828 estatus_node->generic = ghes->generic;
825 estatus = GHES_ESTATUS_FROM_NODE(estatus_node); 829 estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
826 memcpy(estatus, ghes->estatus, len); 830 memcpy(estatus, ghes->estatus, len);
@@ -899,6 +903,11 @@ static int ghes_probe(struct platform_device *ghes_dev)
899 ghes = NULL; 903 ghes = NULL;
900 goto err; 904 goto err;
901 } 905 }
906
907 rc = ghes_edac_register(ghes, &ghes_dev->dev);
908 if (rc < 0)
909 goto err;
910
902 switch (generic->notify.type) { 911 switch (generic->notify.type) {
903 case ACPI_HEST_NOTIFY_POLLED: 912 case ACPI_HEST_NOTIFY_POLLED:
904 ghes->timer.function = ghes_poll_func; 913 ghes->timer.function = ghes_poll_func;
@@ -911,13 +920,13 @@ static int ghes_probe(struct platform_device *ghes_dev)
911 if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) { 920 if (acpi_gsi_to_irq(generic->notify.vector, &ghes->irq)) {
912 pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n", 921 pr_err(GHES_PFX "Failed to map GSI to IRQ for generic hardware error source: %d\n",
913 generic->header.source_id); 922 generic->header.source_id);
914 goto err; 923 goto err_edac_unreg;
915 } 924 }
916 if (request_irq(ghes->irq, ghes_irq_func, 925 if (request_irq(ghes->irq, ghes_irq_func,
917 0, "GHES IRQ", ghes)) { 926 0, "GHES IRQ", ghes)) {
918 pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n", 927 pr_err(GHES_PFX "Failed to register IRQ for generic hardware error source: %d\n",
919 generic->header.source_id); 928 generic->header.source_id);
920 goto err; 929 goto err_edac_unreg;
921 } 930 }
922 break; 931 break;
923 case ACPI_HEST_NOTIFY_SCI: 932 case ACPI_HEST_NOTIFY_SCI:
@@ -943,6 +952,8 @@ static int ghes_probe(struct platform_device *ghes_dev)
943 platform_set_drvdata(ghes_dev, ghes); 952 platform_set_drvdata(ghes_dev, ghes);
944 953
945 return 0; 954 return 0;
955err_edac_unreg:
956 ghes_edac_unregister(ghes);
946err: 957err:
947 if (ghes) { 958 if (ghes) {
948 ghes_fini(ghes); 959 ghes_fini(ghes);
@@ -995,6 +1006,9 @@ static int ghes_remove(struct platform_device *ghes_dev)
995 } 1006 }
996 1007
997 ghes_fini(ghes); 1008 ghes_fini(ghes);
1009
1010 ghes_edac_unregister(ghes);
1011
998 kfree(ghes); 1012 kfree(ghes);
999 1013
1000 platform_set_drvdata(ghes_dev, NULL); 1014 platform_set_drvdata(ghes_dev, NULL);
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 3eb8dc483449..720446cb243e 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -27,6 +27,7 @@ struct ghes {
27struct ghes_estatus_node { 27struct ghes_estatus_node {
28 struct llist_node llnode; 28 struct llist_node llnode;
29 struct acpi_hest_generic *generic; 29 struct acpi_hest_generic *generic;
30 struct ghes *ghes;
30}; 31};
31 32
32struct ghes_estatus_cache { 33struct ghes_estatus_cache {
@@ -43,3 +44,29 @@ enum {
43 GHES_SEV_RECOVERABLE = 0x2, 44 GHES_SEV_RECOVERABLE = 0x2,
44 GHES_SEV_PANIC = 0x3, 45 GHES_SEV_PANIC = 0x3,
45}; 46};
47
48/* From drivers/edac/ghes_edac.c */
49
50#ifdef CONFIG_EDAC_GHES
51void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
52 struct cper_sec_mem_err *mem_err);
53
54int ghes_edac_register(struct ghes *ghes, struct device *dev);
55
56void ghes_edac_unregister(struct ghes *ghes);
57
58#else
59static inline void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
60 struct cper_sec_mem_err *mem_err)
61{
62}
63
64static inline int ghes_edac_register(struct ghes *ghes, struct device *dev)
65{
66 return 0;
67}
68
69static inline void ghes_edac_unregister(struct ghes *ghes)
70{
71}
72#endif