From patchwork Wed Apr 6 15:12:51 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tyler Baicar X-Patchwork-Id: 8763341 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 162E89F39A for ; Wed, 6 Apr 2016 15:16:12 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 983EE20204 for ; Wed, 6 Apr 2016 15:16:09 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 014EA2010E for ; Wed, 6 Apr 2016 15:16:08 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1anp9q-0005PH-7G; Wed, 06 Apr 2016 15:14:14 +0000 Received: from smtp.codeaurora.org ([198.145.29.96]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1anp9k-0005Ex-UC for linux-arm-kernel@lists.infradead.org; Wed, 06 Apr 2016 15:14:11 +0000 Received: from smtp.codeaurora.org (localhost [127.0.0.1]) by smtp.codeaurora.org (Postfix) with ESMTP id C93AE6163B; Wed, 6 Apr 2016 15:13:49 +0000 (UTC) Received: by smtp.codeaurora.org (Postfix, from userid 1000) id C5FC461650; Wed, 6 Apr 2016 15:13:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from tbaicar-lnx.qualcomm.com (unknown [129.46.14.132]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: tbaicar@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 8D9696163B; Wed, 6 Apr 2016 15:13:46 +0000 (UTC) From: Tyler Baicar To: fu.wei@linaro.org, timur@codeaurora.org, harba@codeaurora.org, rruigrok@codeaurora.org, ahs3@redhat.com, catalin.marinas@arm.com, will.deacon@arm.com, rjw@rjwysocki.net, lenb@kernel.org, matt@codeblueprint.co.uk, robert.moore@intel.com, lv.zheng@intel.com, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org, linux-efi@vger.kernel.org, devel@acpica.org Subject: [PATCH V2 2/9] ras: acpi/apei: cper: generic error data entry v3 per ACPI 6.1 Date: Wed, 6 Apr 2016 09:12:51 -0600 Message-Id: <1459955578-24602-3-git-send-email-tbaicar@codeaurora.org> X-Mailer: git-send-email 1.8.2.1 In-Reply-To: <1459955578-24602-1-git-send-email-tbaicar@codeaurora.org> References: <1459955578-24602-1-git-send-email-tbaicar@codeaurora.org> X-Virus-Scanned: ClamAV using ClamSMTP X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160406_081409_276084_6E7C2718 X-CRM114-Status: GOOD ( 17.81 ) X-Spam-Score: -2.9 (--) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Naveen Kaje , Tyler Baicar , "Jonathan \(Zhixiong\) Zhang" MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Currently when a RAS error is reported it is not timestamped. The ACPI 6.1 spec adds the timestamp field to the generic error data entry v3 structure. The timestamp of when the firmware generated the error is now being reported. Signed-off-by: Jonathan (Zhixiong) Zhang Signed-off-by: Richard Ruigrok Signed-off-by: Tyler Baicar Signed-off-by: Naveen Kaje --- drivers/acpi/apei/ghes.c | 35 ++++++++++++-- drivers/firmware/efi/cper.c | 111 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 126 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 9b0543e..a6848706 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -419,7 +419,15 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int int flags = -1; int sec_sev = ghes_severity(gdata->error_severity); struct cper_sec_mem_err *mem_err; - mem_err = (struct cper_sec_mem_err *)(gdata + 1); + struct acpi_hest_generic_data_v300 *gdata_v3 = NULL; + + if ((gdata->revision >> 8) >= 0x03) + gdata_v3 = (struct acpi_hest_generic_data_v300 *)gdata; + + if (gdata_v3) + mem_err = (struct cper_sec_mem_err *)(gdata_v3 + 1); + else + mem_err = (struct cper_sec_mem_err *)(gdata + 1); if (!(mem_err->validation_bits & CPER_MEM_VALID_PA)) return; @@ -449,14 +457,27 @@ static void ghes_do_proc(struct ghes *ghes, { int sev, sec_sev; struct acpi_hest_generic_data *gdata; + struct acpi_hest_generic_data_v300 *gdata_v3 = NULL; + uuid_le sec_type; sev = ghes_severity(estatus->error_severity); apei_estatus_for_each_section(estatus, gdata) { sec_sev = ghes_severity(gdata->error_severity); - if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, + sec_type = *(uuid_le *)gdata->section_type; + + if ((gdata->revision >> 8) >= 0x03) + gdata_v3 = (struct acpi_hest_generic_data_v300 *)gdata; + + if (!uuid_le_cmp(sec_type, CPER_SEC_PLATFORM_MEM)) { struct cper_sec_mem_err *mem_err; - mem_err = (struct cper_sec_mem_err *)(gdata+1); + + if (gdata_v3) + mem_err = (struct cper_sec_mem_err *) + (gdata_v3 + 1); + else + mem_err = (struct cper_sec_mem_err *) + (gdata + 1); ghes_edac_report_mem_error(ghes, sev, mem_err); arch_apei_report_mem_error(sev, mem_err); @@ -466,7 +487,13 @@ static void ghes_do_proc(struct ghes *ghes, else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, CPER_SEC_PCIE)) { struct cper_sec_pcie *pcie_err; - pcie_err = (struct cper_sec_pcie *)(gdata+1); + + if (gdata_v3) + pcie_err = (struct cper_sec_pcie *) + (gdata_v3 + 1); + else + pcie_err = (struct cper_sec_pcie *) + (gdata + 1); if (sev == GHES_SEV_RECOVERABLE && sec_sev == GHES_SEV_RECOVERABLE && pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index d425374..23f62962 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #define INDENT_SP " " @@ -392,6 +394,10 @@ static void cper_estatus_print_section( uuid_le *sec_type = (uuid_le *)gdata->section_type; __u16 severity; char newpfx[64]; + struct acpi_hest_generic_data_v300 *gdata_v3 = NULL; + + if ((gdata->revision >> 8) >= 0x03) + gdata_v3 = (struct acpi_hest_generic_data_v300 *)gdata; severity = gdata->error_severity; printk("%s""Error %d, type: %s\n", pfx, sec_no, @@ -403,14 +409,24 @@ static void cper_estatus_print_section( snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) { - struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1); + struct cper_sec_proc_generic *proc_err; + + if (gdata_v3) + proc_err = (void *)(gdata_v3 + 1); + else + proc_err = (void *)(gdata + 1); printk("%s""section_type: general processor error\n", newpfx); if (gdata->error_data_length >= sizeof(*proc_err)) cper_print_proc_generic(newpfx, proc_err); else goto err_section_too_small; } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) { - struct cper_sec_mem_err *mem_err = (void *)(gdata + 1); + struct cper_sec_mem_err *mem_err; + + if (gdata_v3) + mem_err = (void *)(gdata_v3 + 1); + else + mem_err = (void *)(gdata + 1); printk("%s""section_type: memory error\n", newpfx); if (gdata->error_data_length >= sizeof(struct cper_sec_mem_err_old)) @@ -419,7 +435,12 @@ static void cper_estatus_print_section( else goto err_section_too_small; } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) { - struct cper_sec_pcie *pcie = (void *)(gdata + 1); + struct cper_sec_pcie *pcie; + + if (gdata_v3) + pcie = (void *)(gdata_v3 + 1); + else + pcie = (void *)(gdata + 1); printk("%s""section_type: PCIe error\n", newpfx); if (gdata->error_data_length >= sizeof(*pcie)) cper_print_pcie(newpfx, pcie, gdata); @@ -434,10 +455,38 @@ err_section_too_small: pr_err(FW_WARN "error section length is too small\n"); } +static void cper_estatus_print_section_v300(const char *pfx, + const struct acpi_hest_generic_data_v300 *gdata, int sec_no) +{ + __u8 hour, min, sec, day, mon, year, century, *timestamp; + + if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { + timestamp = (__u8 *)&(gdata->time_stamp); + memcpy(&sec, timestamp, 1); + memcpy(&min, timestamp + 1, 1); + memcpy(&hour, timestamp + 2, 1); + memcpy(&day, timestamp + 4, 1); + memcpy(&mon, timestamp + 5, 1); + memcpy(&year, timestamp + 6, 1); + memcpy(¢ury, timestamp + 7, 1); + printk("%stime: ", pfx); + printk("%7s", 0x01 & *(timestamp + 3) ? "precise" : ""); + printk(" %02d:%02d:%02d %02d%02d-%02d-%02d\n", + bcd2bin(hour), bcd2bin(min), bcd2bin(sec), + bcd2bin(century), bcd2bin(year), bcd2bin(mon), + bcd2bin(day)); + } + + cper_estatus_print_section(pfx, + (const struct acpi_hest_generic_data *)gdata, + sec_no); +} + void cper_estatus_print(const char *pfx, const struct acpi_hest_generic_status *estatus) { struct acpi_hest_generic_data *gdata; + struct acpi_hest_generic_data_v300 *gdata_v3 = NULL; unsigned int data_len, gedata_len; int sec_no = 0; char newpfx[64]; @@ -451,13 +500,28 @@ void cper_estatus_print(const char *pfx, printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); data_len = estatus->data_length; gdata = (struct acpi_hest_generic_data *)(estatus + 1); + if ((gdata->revision >> 8) >= 0x03) + gdata_v3 = (struct acpi_hest_generic_data_v300 *)gdata; + snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP); - while (data_len >= sizeof(*gdata)) { - gedata_len = gdata->error_data_length; - cper_estatus_print_section(newpfx, gdata, sec_no); - data_len -= gedata_len + sizeof(*gdata); - gdata = (void *)(gdata + 1) + gedata_len; - sec_no++; + + if (gdata_v3) { + while (data_len >= sizeof(*gdata_v3)) { + gedata_len = gdata_v3->error_data_length; + cper_estatus_print_section_v300(newpfx, gdata_v3, + sec_no); + data_len -= gedata_len + sizeof(*gdata_v3); + gdata_v3 = (void *)(gdata_v3 + 1) + gedata_len; + sec_no++; + } + } else { + while (data_len >= sizeof(*gdata)) { + gedata_len = gdata->error_data_length; + cper_estatus_print_section(newpfx, gdata, sec_no); + data_len -= gedata_len + sizeof(*gdata); + gdata = (void *)(gdata + 1) + gedata_len; + sec_no++; + } } } EXPORT_SYMBOL_GPL(cper_estatus_print); @@ -478,6 +542,7 @@ EXPORT_SYMBOL_GPL(cper_estatus_check_header); int cper_estatus_check(const struct acpi_hest_generic_status *estatus) { struct acpi_hest_generic_data *gdata; + struct acpi_hest_generic_data_v300 *gdata_v3 = NULL; unsigned int data_len, gedata_len; int rc; @@ -486,15 +551,29 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus) return rc; data_len = estatus->data_length; gdata = (struct acpi_hest_generic_data *)(estatus + 1); - while (data_len >= sizeof(*gdata)) { - gedata_len = gdata->error_data_length; - if (gedata_len > data_len - sizeof(*gdata)) + + if ((gdata->revision >> 8) >= 0x03) { + gdata_v3 = (struct acpi_hest_generic_data_v300 *)gdata; + while (data_len >= sizeof(*gdata_v3)) { + gedata_len = gdata_v3->error_data_length; + if (gedata_len > data_len - sizeof(*gdata_v3)) + return -EINVAL; + data_len -= gedata_len + sizeof(*gdata_v3); + gdata_v3 = (void *)(gdata_v3 + 1) + gedata_len; + } + if (data_len) + return -EINVAL; + } else { + while (data_len >= sizeof(*gdata)) { + gedata_len = gdata->error_data_length; + if (gedata_len > data_len - sizeof(*gdata)) + return -EINVAL; + data_len -= gedata_len + sizeof(*gdata); + gdata = (void *)(gdata + 1) + gedata_len; + } + if (data_len) return -EINVAL; - data_len -= gedata_len + sizeof(*gdata); - gdata = (void *)(gdata + 1) + gedata_len; } - if (data_len) - return -EINVAL; return 0; }