aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2013-02-15 04:10:39 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-02-25 17:41:51 -0500
commit21480547c8b85be6c08c4d77ed514673b73eda8a (patch)
tree1ea79a66c55128e36cfc4334bd6f00db3593e9fc /drivers/acpi/apei
parent40e064153814ce534a28714b25cb98259f107d96 (diff)
ghes: add the needed hooks for EDAC error report
In order to allow reporting errors via EDAC, add hooks for: 1) register an EDAC driver; 2) unregister an EDAC driver; 3) report errors via EDAC. As the EDAC driver will need to access the ghes structure, adds it as one of the parameters for ghes_do_proc. Acked-by: Huang Ying <ying.huang@intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/acpi/apei')
-rw-r--r--drivers/acpi/apei/ghes.c24
1 files changed, 19 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);