From patchwork Fri May 29 23:29:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alex Hung X-Patchwork-Id: 1301083 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=fwts-devel-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 49Ygkj0kGZz9sRN; Sat, 30 May 2020 09:29:17 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1jeoR8-00053v-HY; Fri, 29 May 2020 23:29:14 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1jeoR6-00053p-Gm for fwts-devel@lists.ubuntu.com; Fri, 29 May 2020 23:29:12 +0000 Received: from 2.general.alexhung.us.vpn ([10.172.65.255] helo=canonical.com) by youngberry.canonical.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1jeoR5-0006NO-WB; Fri, 29 May 2020 23:29:12 +0000 From: Alex Hung To: fwts-devel@lists.ubuntu.com Subject: [PATCH] acpi/nvdimm: add tests for nvdimm devices Date: Fri, 29 May 2020 17:29:09 -0600 Message-Id: <20200529232909.135909-1-alex.hung@canonical.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 X-BeenThere: fwts-devel@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Firmware Test Suite Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: fwts-devel-bounces@lists.ubuntu.com Sender: "fwts-devel" Signed-off-by: Alex Hung --- src/Makefile.am | 1 + src/acpi/devices/nvdimm/nvdimm.c | 299 +++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 src/acpi/devices/nvdimm/nvdimm.c diff --git a/src/Makefile.am b/src/Makefile.am index e0093aef..4bc9c7d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ fwts_SOURCES = main.c \ acpi/devices/buttons/power_button.c \ acpi/devices/buttons/sleep_button.c \ acpi/devices/lid/lid.c \ + acpi/devices/nvdimm/nvdimm.c \ acpi/devices/sensor/als.c \ acpi/devices/time/time.c \ acpi/devices/wpc/wpc.c \ diff --git a/src/acpi/devices/nvdimm/nvdimm.c b/src/acpi/devices/nvdimm/nvdimm.c new file mode 100644 index 00000000..507fa082 --- /dev/null +++ b/src/acpi/devices/nvdimm/nvdimm.c @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2017-2020 Canonical + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ +#include "fwts.h" + +#if defined(FWTS_HAS_ACPI) + +#include "fwts_acpi_object_eval.h" +#include +#include +#include +#include +#include + +#define FWTS_ACPI_NVDIMM_HID "ACPI0012" + +static ACPI_HANDLE device; + +static ACPI_STATUS get_device_handle(ACPI_HANDLE handle, uint32_t level, + void *context, void **ret_val) +{ + FWTS_UNUSED(level); + FWTS_UNUSED(context); + FWTS_UNUSED(ret_val); + + device = handle; + return AE_CTRL_TERMINATE; +} + +static int acpi_nvdimm_init(fwts_framework *fw) +{ + ACPI_STATUS status; + + if (fwts_acpica_init(fw) != FWTS_OK) + return FWTS_ERROR; + + status = AcpiGetDevices(FWTS_ACPI_NVDIMM_HID, get_device_handle, NULL, NULL); + if (ACPI_FAILURE(status)) { + fwts_log_error(fw, "Cannot find the ACPI device"); + return FWTS_ERROR; + } + + if (!device) { + fwts_log_error(fw, "ACPI NVDIMM device does not exist, skipping test"); + fwts_acpica_deinit(); + return FWTS_SKIP; + } else { + ACPI_BUFFER buffer; + char full_name[128]; + + buffer.Length = sizeof(full_name); + buffer.Pointer = full_name; + + status = AcpiGetName(device, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_SUCCESS(status)) { + fwts_log_info_verbatim(fw, "ACPI NVDIMM Device: %s", full_name); + fwts_log_nl(fw); + } + } + + return FWTS_OK; +} + +static void check_nvdimm_status( + fwts_framework *fw, + char *name, + uint16_t status, + bool *failed) +{ + if (status > 6) { + *failed = true; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "MethodBadStatus", + "%s: Expected Status to be 0..6, got %" PRIx16, + name, status); + } +} + +static void check_nvdimm_extended_status( + fwts_framework *fw, + char *name, + uint16_t ext_status, + uint16_t expected, + bool *failed) +{ + if (ext_status != expected) { + *failed = true; + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "MethodBadExtendedStatus", + "%s: Expected Extended Status to be %" PRIx16 + ", got %" PRIx16, name, expected, ext_status); + } +} + +static void method_test_NCH_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + bool failed = false; + nch_return_t *ret; + + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK) + return; + + if (fwts_method_buffer_size(fw, name, obj, 64) != FWTS_OK) + failed = true; + + ret = (nch_return_t *) obj->Buffer.Pointer; + check_nvdimm_status(fw, name, ret->status, &failed); + check_nvdimm_extended_status(fw, name, ret->extended_status, 0, &failed); + fwts_acpi_reserved_bits_check(fw, "_NCH", "Validation Flags", + ret->extended_status, sizeof(uint16_t), 2, 15, &failed); + + /* Health Status Flags [2..7], [11.15], [19..31] are reserved */ + fwts_acpi_reserved_bits_check(fw, "_NCH", "Health Status Flags", + ret->health_status_flags, sizeof(uint32_t), 2, 7, &failed); + fwts_acpi_reserved_bits_check(fw, "_NCH", "Health Status Flags", + ret->health_status_flags, sizeof(uint32_t), 11, 15, &failed); + fwts_acpi_reserved_bits_check(fw, "_NCH", "Health Status Flags", + ret->health_status_flags, sizeof(uint32_t), 19, 31, &failed); + + fwts_acpi_reserved_bits_check(fw, "_NCH", "Health Status Attributes", + ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed); + + if (!failed) + fwts_method_passed_sane(fw, name, "buffer"); +} + +static int method_test_NCH(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, &device, + "_NCH", NULL, 0, method_test_NCH_return, NULL); +} + +static void method_test_NBS_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + bool failed = false; + nbs_return_t *ret; + + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK) + return; + + if (fwts_method_buffer_size(fw, name, obj, 64) != FWTS_OK) + failed = true; + + ret = (nbs_return_t *) obj->Buffer.Pointer; + check_nvdimm_status(fw, name, ret->status, &failed); + check_nvdimm_extended_status(fw, name, ret->extended_status, 0, &failed); + fwts_acpi_reserved_bits_check(fw, "_NBS", "Validation Flags", + ret->validation_flags, sizeof(uint16_t), 1, 15, &failed); + + if (!failed) + fwts_method_passed_sane(fw, name, "buffer"); +} + +static int method_test_NBS(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, &device, + "_NBS", NULL, 0, method_test_NBS_return, NULL); +} + +static void method_test_NIC_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + bool failed = false; + nic_return_t *ret; + + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK) + return; + + if (fwts_method_buffer_size(fw, name, obj, 64) != FWTS_OK) + failed = true; + + ret = (nic_return_t *) obj->Buffer.Pointer; + check_nvdimm_status(fw, name, ret->status, &failed); + check_nvdimm_extended_status(fw, name, ret->extended_status, 0, &failed); + + /* Health Error Injection Capabilities [2..7], [11.15], [19..31] are reserved */ + fwts_acpi_reserved_bits_check(fw, "_NIC", "Health Error Injection Capabilities", + ret->health_error_injection, sizeof(uint32_t), 2, 7, &failed); + fwts_acpi_reserved_bits_check(fw, "_NIC", "Health Error Injection Capabilities", + ret->health_error_injection, sizeof(uint32_t), 11, 15, &failed); + fwts_acpi_reserved_bits_check(fw, "_NIC", "Health Error Injection Capabilities", + ret->health_error_injection, sizeof(uint32_t), 19, 31, &failed); + + fwts_acpi_reserved_bits_check(fw, "_NIC", "Health Status Attributes Capabilities", + ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed); + + if (!failed) + fwts_method_passed_sane(fw, name, "buffer"); +} + +static int method_test_NIC(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, &device, + "_NIC", NULL, 0, method_test_NIC_return, NULL); +} + + +static void method_test_NIH_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + bool failed = false; + nih_return_t *ret; + + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK) + return; + + if (fwts_method_buffer_size(fw, name, obj, 64) != FWTS_OK) + failed = true; + + ret = (nih_return_t *) obj->Buffer.Pointer; + check_nvdimm_status(fw, name, ret->status, &failed); + check_nvdimm_extended_status(fw, name, ret->extended_status, 1, &failed); + + if (!failed) + fwts_method_passed_sane(fw, name, "buffer"); +} + +static int method_test_NIH(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, &device, + "_NIH", NULL, 0, method_test_NIH_return, NULL); +} + +/* EvaluateD evice Identification Objects - all are optional */ +static int method_test_HID(fwts_framework *fw) +{ + return fwts_method_test_HID(fw, &device); +} + +static fwts_framework_minor_test acpi_nvdimm_tests[] = { + /* Device Specific Objects */ + { method_test_NCH, "Test _NCH (NVDIMM Current Health Information)." }, + { method_test_NBS, "Test _NBS (NVDIMM Boot Status)." }, + { method_test_NIC, "Test _NIC (NVDIMM Health Error Injection Capabilities)." }, + { method_test_NIH, "Test _NIH (NVDIMM Inject/Clear Health Errors)." }, + /* Device Identification Objects - all are optional */ + { method_test_HID, "Test _HID (Hardware ID)." }, + { NULL, NULL } +}; + +static int acpi_nvdimm_deinit(fwts_framework *fw) +{ + FWTS_UNUSED(fw); + fwts_acpica_deinit(); + + return FWTS_OK; +} + +static fwts_framework_ops acpi_nvdimm_ops = { + .description = "NVDIMM device test", + .init = acpi_nvdimm_init, + .deinit = acpi_nvdimm_deinit, + .minor_tests = acpi_nvdimm_tests +}; + +FWTS_REGISTER("acpi_nvdimm", &acpi_nvdimm_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI) + +#endif