diff options
-rw-r--r-- | drivers/acpi/apei/ghes.c | 24 | ||||
-rw-r--r-- | include/acpi/ghes.h | 27 |
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 | ||
412 | static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) | 412 | static 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); |
643 | out: | 646 | out: |
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; |
955 | err_edac_unreg: | ||
956 | ghes_edac_unregister(ghes); | ||
946 | err: | 957 | err: |
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 { | |||
27 | struct ghes_estatus_node { | 27 | struct 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 | ||
32 | struct ghes_estatus_cache { | 33 | struct 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 | ||
51 | void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | ||
52 | struct cper_sec_mem_err *mem_err); | ||
53 | |||
54 | int ghes_edac_register(struct ghes *ghes, struct device *dev); | ||
55 | |||
56 | void ghes_edac_unregister(struct ghes *ghes); | ||
57 | |||
58 | #else | ||
59 | static inline void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | ||
60 | struct cper_sec_mem_err *mem_err) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | static inline int ghes_edac_register(struct ghes *ghes, struct device *dev) | ||
65 | { | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static inline void ghes_edac_unregister(struct ghes *ghes) | ||
70 | { | ||
71 | } | ||
72 | #endif | ||