aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTyler Baicar <tbaicar@codeaurora.org>2017-06-21 14:17:05 -0400
committerWill Deacon <will.deacon@arm.com>2017-06-22 10:43:47 -0400
commitbbcc2e7b642ed241651fee50ac6ed59643cb1736 (patch)
tree695cd84d0db3136d5a6fb397626712d7992d8fa8
parent42aa560446622da6c33dce54fc8f4cd81516e906 (diff)
ras: acpi/apei: cper: add support for generic data v3 structure
The ACPI 6.1 spec adds a new revision of the generic error data entry structure. Add support to handle the new structure as well as properly verify and iterate through the generic data entries. Signed-off-by: Tyler Baicar <tbaicar@codeaurora.org> CC: Jonathan (Zhixiong) Zhang <zjzhang@codeaurora.org> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--drivers/acpi/apei/ghes.c11
-rw-r--r--drivers/firmware/efi/cper.c37
-rw-r--r--include/acpi/ghes.h36
3 files changed, 63 insertions, 21 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 866d244c6311..81e06e3cb08f 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -428,8 +428,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
428 unsigned long pfn; 428 unsigned long pfn;
429 int flags = -1; 429 int flags = -1;
430 int sec_sev = ghes_severity(gdata->error_severity); 430 int sec_sev = ghes_severity(gdata->error_severity);
431 struct cper_sec_mem_err *mem_err; 431 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
432 mem_err = (struct cper_sec_mem_err *)(gdata + 1);
433 432
434 if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) 433 if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
435 return; 434 return;
@@ -466,8 +465,8 @@ static void ghes_do_proc(struct ghes *ghes,
466 sec_type = (guid_t *)gdata->section_type; 465 sec_type = (guid_t *)gdata->section_type;
467 sec_sev = ghes_severity(gdata->error_severity); 466 sec_sev = ghes_severity(gdata->error_severity);
468 if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { 467 if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
469 struct cper_sec_mem_err *mem_err; 468 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
470 mem_err = (struct cper_sec_mem_err *)(gdata+1); 469
471 ghes_edac_report_mem_error(ghes, sev, mem_err); 470 ghes_edac_report_mem_error(ghes, sev, mem_err);
472 471
473 arch_apei_report_mem_error(sev, mem_err); 472 arch_apei_report_mem_error(sev, mem_err);
@@ -475,8 +474,8 @@ static void ghes_do_proc(struct ghes *ghes,
475 } 474 }
476#ifdef CONFIG_ACPI_APEI_PCIEAER 475#ifdef CONFIG_ACPI_APEI_PCIEAER
477 else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 476 else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
478 struct cper_sec_pcie *pcie_err; 477 struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
479 pcie_err = (struct cper_sec_pcie *)(gdata+1); 478
480 if (sev == GHES_SEV_RECOVERABLE && 479 if (sev == GHES_SEV_RECOVERABLE &&
481 sec_sev == GHES_SEV_RECOVERABLE && 480 sec_sev == GHES_SEV_RECOVERABLE &&
482 pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && 481 pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index d42537425438..902475704311 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -32,6 +32,7 @@
32#include <linux/acpi.h> 32#include <linux/acpi.h>
33#include <linux/pci.h> 33#include <linux/pci.h>
34#include <linux/aer.h> 34#include <linux/aer.h>
35#include <acpi/ghes.h>
35 36
36#define INDENT_SP " " 37#define INDENT_SP " "
37 38
@@ -386,8 +387,9 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
386 pfx, pcie->bridge.secondary_status, pcie->bridge.control); 387 pfx, pcie->bridge.secondary_status, pcie->bridge.control);
387} 388}
388 389
389static void cper_estatus_print_section( 390static void
390 const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no) 391cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
392 int sec_no)
391{ 393{
392 uuid_le *sec_type = (uuid_le *)gdata->section_type; 394 uuid_le *sec_type = (uuid_le *)gdata->section_type;
393 __u16 severity; 395 __u16 severity;
@@ -403,14 +405,16 @@ static void cper_estatus_print_section(
403 405
404 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); 406 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
405 if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { 407 if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
406 struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); 408 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
409
407 printk("%s""section_type: general processor error\n", newpfx); 410 printk("%s""section_type: general processor error\n", newpfx);
408 if (gdata->error_data_length >= sizeof(*proc_err)) 411 if (gdata->error_data_length >= sizeof(*proc_err))
409 cper_print_proc_generic(newpfx, proc_err); 412 cper_print_proc_generic(newpfx, proc_err);
410 else 413 else
411 goto err_section_too_small; 414 goto err_section_too_small;
412 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { 415 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
413 struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); 416 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
417
414 printk("%s""section_type: memory error\n", newpfx); 418 printk("%s""section_type: memory error\n", newpfx);
415 if (gdata->error_data_length >= 419 if (gdata->error_data_length >=
416 sizeof(struct cper_sec_mem_err_old)) 420 sizeof(struct cper_sec_mem_err_old))
@@ -419,7 +423,8 @@ static void cper_estatus_print_section(
419 else 423 else
420 goto err_section_too_small; 424 goto err_section_too_small;
421 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { 425 } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
422 struct cper_sec_pcie *pcie = (void *)(gdata + 1); 426 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
427
423 printk("%s""section_type: PCIe error\n", newpfx); 428 printk("%s""section_type: PCIe error\n", newpfx);
424 if (gdata->error_data_length >= sizeof(*pcie)) 429 if (gdata->error_data_length >= sizeof(*pcie))
425 cper_print_pcie(newpfx, pcie, gdata); 430 cper_print_pcie(newpfx, pcie, gdata);
@@ -438,7 +443,7 @@ void cper_estatus_print(const char *pfx,
438 const struct acpi_hest_generic_status *estatus) 443 const struct acpi_hest_generic_status *estatus)
439{ 444{
440 struct acpi_hest_generic_data *gdata; 445 struct acpi_hest_generic_data *gdata;
441 unsigned int data_len, gedata_len; 446 unsigned int data_len;
442 int sec_no = 0; 447 int sec_no = 0;
443 char newpfx[64]; 448 char newpfx[64];
444 __u16 severity; 449 __u16 severity;
@@ -452,11 +457,11 @@ void cper_estatus_print(const char *pfx,
452 data_len = estatus->data_length; 457 data_len = estatus->data_length;
453 gdata = (struct acpi_hest_generic_data *)(estatus + 1); 458 gdata = (struct acpi_hest_generic_data *)(estatus + 1);
454 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); 459 snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
455 while (data_len >= sizeof(*gdata)) { 460
456 gedata_len = gdata->error_data_length; 461 while (data_len >= acpi_hest_get_size(gdata)) {
457 cper_estatus_print_section(newpfx, gdata, sec_no); 462 cper_estatus_print_section(newpfx, gdata, sec_no);
458 data_len -= gedata_len + sizeof(*gdata); 463 data_len -= acpi_hest_get_record_size(gdata);
459 gdata = (void *)(gdata + 1) + gedata_len; 464 gdata = acpi_hest_get_next(gdata);
460 sec_no++; 465 sec_no++;
461 } 466 }
462} 467}
@@ -486,12 +491,14 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
486 return rc; 491 return rc;
487 data_len = estatus->data_length; 492 data_len = estatus->data_length;
488 gdata = (struct acpi_hest_generic_data *)(estatus + 1); 493 gdata = (struct acpi_hest_generic_data *)(estatus + 1);
489 while (data_len >= sizeof(*gdata)) { 494
490 gedata_len = gdata->error_data_length; 495 while (data_len >= acpi_hest_get_size(gdata)) {
491 if (gedata_len > data_len - sizeof(*gdata)) 496 gedata_len = acpi_hest_get_error_length(gdata);
497 if (gedata_len > data_len - acpi_hest_get_size(gdata))
492 return -EINVAL; 498 return -EINVAL;
493 data_len -= gedata_len + sizeof(*gdata); 499
494 gdata = (void *)(gdata + 1) + gedata_len; 500 data_len -= acpi_hest_get_record_size(gdata);
501 gdata = acpi_hest_get_next(gdata);
495 } 502 }
496 if (data_len) 503 if (data_len)
497 return -EINVAL; 504 return -EINVAL;
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 68f088a92398..8f8fea004df5 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -73,3 +73,39 @@ static inline void ghes_edac_unregister(struct ghes *ghes)
73{ 73{
74} 74}
75#endif 75#endif
76
77static inline int acpi_hest_get_version(struct acpi_hest_generic_data *gdata)
78{
79 return gdata->revision >> 8;
80}
81
82static inline void *acpi_hest_get_payload(struct acpi_hest_generic_data *gdata)
83{
84 if (acpi_hest_get_version(gdata) >= 3)
85 return (void *)(((struct acpi_hest_generic_data_v300 *)(gdata)) + 1);
86
87 return gdata + 1;
88}
89
90static inline int acpi_hest_get_error_length(struct acpi_hest_generic_data *gdata)
91{
92 return ((struct acpi_hest_generic_data *)(gdata))->error_data_length;
93}
94
95static inline int acpi_hest_get_size(struct acpi_hest_generic_data *gdata)
96{
97 if (acpi_hest_get_version(gdata) >= 3)
98 return sizeof(struct acpi_hest_generic_data_v300);
99
100 return sizeof(struct acpi_hest_generic_data);
101}
102
103static inline int acpi_hest_get_record_size(struct acpi_hest_generic_data *gdata)
104{
105 return (acpi_hest_get_size(gdata) + acpi_hest_get_error_length(gdata));
106}
107
108static inline void *acpi_hest_get_next(struct acpi_hest_generic_data *gdata)
109{
110 return (void *)(gdata) + acpi_hest_get_record_size(gdata);
111}