[V2] acpi/method: add tests for NVDIMM control methods for ACPI 6.3

Message ID 20190212054236.5221-1-alex.hung@canonical.com
State Accepted
Headers show
Series
  • [V2] acpi/method: add tests for NVDIMM control methods for ACPI 6.3
Related show

Commit Message

Alex Hung Feb. 12, 2019, 5:42 a.m.
Signed-off-by: Alex Hung <alex.hung@canonical.com>
---
 src/acpi/method/method.c                | 286 ++++++++++++++++++++++++
 src/lib/include/fwts_acpi_object_eval.h |  40 ++++
 2 files changed, 326 insertions(+)

Comments

Colin Ian King Feb. 12, 2019, 9:03 a.m. | #1
On 12/02/2019 05:42, Alex Hung wrote:
> Signed-off-by: Alex Hung <alex.hung@canonical.com>
> ---
>  src/acpi/method/method.c                | 286 ++++++++++++++++++++++++
>  src/lib/include/fwts_acpi_object_eval.h |  40 ++++
>  2 files changed, 326 insertions(+)
> 
> diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c
> index 654112d9..48a5c039 100644
> --- a/src/acpi/method/method.c
> +++ b/src/acpi/method/method.c
> @@ -138,6 +138,11 @@
>   * _MSG 	 Y
>   * _MSM 	 N
>   * _MTL 	 Y
> + * _NBS 	 Y
> + * _NCH 	 Y
> + * _NIC 	 Y
> + * _NIH 	 Y
> + * _NIG 	 Y
>   * _NTT 	 Y
>   * _OFF 	 Y
>   * _ON_ 	 Y
> @@ -3574,6 +3579,280 @@ static int method_test_TIV(fwts_framework *fw)
>  		"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
>  }
>  
> +/*
> + * Section 9.20 NVDIMM Devices
> + */
> +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_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NBSBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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 method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NBS", NULL, 0, method_test_NBS_return, NULL);
> +}
> +
> +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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NCHBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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 method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NCH", NULL, 0, method_test_NCH_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NICBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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 method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NIHBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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)
> +{
> +	ACPI_OBJECT arg0;
> +	char data[64];
> +	int result;
> +	int i, j;
> +
> +	memset(data, 0, sizeof(data));
> +	arg0.Type = ACPI_TYPE_BUFFER;
> +	arg0.Buffer.Length = 64;
> +	arg0.Buffer.Pointer = (void *)data;
> +
> +	/* not permanent (j = 0) and permanent (j = 1) errors  */
> +	for (j = 0; j <= 1; j++) {
> +		/* inject (i = 1) and clear (i = 2) errors */
> +		for (i = 1; i <= 2; i++) {
> +			data[0] = i;
> +			data[4] = 3;
> +			data[5] = 7;
> +			data[6] = 7;
> +			data[8] = j;
> +
> +			result = method_evaluate_method(fw, METHOD_OPTIONAL,
> +				"_NIH", &arg0, 1, method_test_NIH_return, NULL);
> +
> +			if (result != FWTS_OK)
> +				return result;
> +		}
> +	}
> +
> +	return FWTS_OK;
> +}
> +
> +static void method_test_NIG_return(
> +	fwts_framework *fw,
> +	char *name,
> +	ACPI_BUFFER *buf,
> +	ACPI_OBJECT *obj,
> +	void *private)
> +{
> +	bool failed = false;
> +	nig_return_t *ret;
> +
> +	FWTS_UNUSED(private);
> +
> +	if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> +		return;
> +
> +	if (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NIGBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	ret = (nig_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, "_NIG", "Validation Flags", ret->validation_flags, sizeof(uint16_t), 2, 15, &failed);
> +
> +	/* Injected Health Status Errors [2..7], [11.15], [19..31] are reserved */
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 2, 7, &failed);
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 11, 15, &failed);
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 19, 31, &failed);
> +
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Health Status Attributes of Injected Errors", ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed);
> +
> +	if (!failed)
> +		fwts_method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_NIG(fwts_framework *fw)
> +{
> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NIG", NULL, 0, method_test_NIG_return, NULL);
> +}
>  
>  /*
>   * Section 10.1 Smart Battery
> @@ -5896,6 +6175,13 @@ static fwts_framework_minor_test method_tests[] = {
>  	{ method_test_TIP, "Test _TIP (Expired Timer Wake Policy)." },
>  	{ method_test_TIV, "Test _TIV (Timer Values)." },
>  
> +	/* Section 9.20 NVDIMM Devices */
> +	{ method_test_NBS, "Test _NBS (NVDIMM Boot Status)." },
> +	{ method_test_NCH, "Test _NCH (NVDIMM Current Health Information)." },
> +	{ method_test_NIC, "Test _NIC (NVDIMM Health Error Injection Capabilities)." },
> +	{ method_test_NIH, "Test _NIH (NVDIMM Inject/Clear Health Errors)." },
> +	{ method_test_NIG, "Test _NIG (NVDIMM Inject Health Error Status)." },
> +
>  	/* Section 10.1 Smart Battery */
>  
>  	{ method_test_SBS, "Test _SBS (Smart Battery Subsystem)." },
> diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h
> index 4a7c5ed9..565af728 100644
> --- a/src/lib/include/fwts_acpi_object_eval.h
> +++ b/src/lib/include/fwts_acpi_object_eval.h
> @@ -66,6 +66,46 @@ typedef struct {
>  	uint8_t		pad2[3];
>  } __attribute__ ((packed)) fwts_acpi_time_buffer;
>  
> +/* Returns for NVDIMM control methods */
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	health_status_flags;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[50];
> +}  __attribute__ ((packed)) nch_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	data_loss_count;
> +	uint8_t		reserved[54];
> +}  __attribute__ ((packed)) nbs_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint32_t	health_error_injection;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[52];
> +}  __attribute__ ((packed)) nic_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +}  __attribute__ ((packed)) nih_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	health_status_errors;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[50];
> +}  __attribute__ ((packed)) nig_return_t;
> +
>  #define fwts_method_check_type(fw, name, buf, type) 			\
>  	fwts_method_check_type__(fw, name, buf, type, #type)
>  
> 
Thanks Alex

Acked-by: Colin Ian King <colin.king@canonical.com>
ivanhu Feb. 18, 2019, 10:09 a.m. | #2
On 2/12/19 1:42 PM, Alex Hung wrote:
> Signed-off-by: Alex Hung <alex.hung@canonical.com>
> ---
>  src/acpi/method/method.c                | 286 ++++++++++++++++++++++++
>  src/lib/include/fwts_acpi_object_eval.h |  40 ++++
>  2 files changed, 326 insertions(+)
>
> diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c
> index 654112d9..48a5c039 100644
> --- a/src/acpi/method/method.c
> +++ b/src/acpi/method/method.c
> @@ -138,6 +138,11 @@
>   * _MSG 	 Y
>   * _MSM 	 N
>   * _MTL 	 Y
> + * _NBS 	 Y
> + * _NCH 	 Y
> + * _NIC 	 Y
> + * _NIH 	 Y
> + * _NIG 	 Y
>   * _NTT 	 Y
>   * _OFF 	 Y
>   * _ON_ 	 Y
> @@ -3574,6 +3579,280 @@ static int method_test_TIV(fwts_framework *fw)
>  		"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
>  }
>  
> +/*
> + * Section 9.20 NVDIMM Devices
> + */
> +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_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NBSBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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);
Should check the rest return bytes are reserved?
> +
> +	if (!failed)
> +		fwts_method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_NBS(fwts_framework *fw)
> +{
> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NBS", NULL, 0, method_test_NBS_return, NULL);
> +}
> +
> +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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NCHBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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);
> +
Should check the rest return bytes are reserved?
> +	if (!failed)
> +		fwts_method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_NCH(fwts_framework *fw)
> +{
> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NCH", NULL, 0, method_test_NCH_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NICBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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);
same here.
> +
> +	if (!failed)
> +		fwts_method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_NIC(fwts_framework *fw)
> +{
> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_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 (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NIHBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	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)
> +{
> +	ACPI_OBJECT arg0;
> +	char data[64];
> +	int result;
> +	int i, j;
> +
> +	memset(data, 0, sizeof(data));
> +	arg0.Type = ACPI_TYPE_BUFFER;
> +	arg0.Buffer.Length = 64;
> +	arg0.Buffer.Pointer = (void *)data;
> +
> +	/* not permanent (j = 0) and permanent (j = 1) errors  */
> +	for (j = 0; j <= 1; j++) {
> +		/* inject (i = 1) and clear (i = 2) errors */
> +		for (i = 1; i <= 2; i++) {
> +			data[0] = i;
> +			data[4] = 3;
> +			data[5] = 7;
> +			data[6] = 7;
> +			data[8] = j;
> +
> +			result = method_evaluate_method(fw, METHOD_OPTIONAL,
> +				"_NIH", &arg0, 1, method_test_NIH_return, NULL);
> +
> +			if (result != FWTS_OK)
> +				return result;
> +		}
> +	}
> +
> +	return FWTS_OK;
> +}
> +
> +static void method_test_NIG_return(
> +	fwts_framework *fw,
> +	char *name,
> +	ACPI_BUFFER *buf,
> +	ACPI_OBJECT *obj,
> +	void *private)
> +{
> +	bool failed = false;
> +	nig_return_t *ret;
> +
> +	FWTS_UNUSED(private);
> +
> +	if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
> +		return;
> +
> +	if (obj->Buffer.Length != 64) {
> +		failed = true;
> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
> +			"Method_NIGBadBufferSize",
> +			"%s should return a buffer of 64 bytes, but "
> +			"instead just returned %" PRIu32,
> +			name, obj->Buffer.Length);
> +	}
> +
> +	ret = (nig_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, "_NIG", "Validation Flags", ret->validation_flags, sizeof(uint16_t), 2, 15, &failed);
> +
> +	/* Injected Health Status Errors [2..7], [11.15], [19..31] are reserved */
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 2, 7, &failed);
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 11, 15, &failed);
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 19, 31, &failed);
> +
> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Health Status Attributes of Injected Errors", ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed);
> +
same here.
> +	if (!failed)
> +		fwts_method_passed_sane(fw, name, "buffer");
> +}
> +
> +static int method_test_NIG(fwts_framework *fw)
> +{
> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
> +		"_NIG", NULL, 0, method_test_NIG_return, NULL);
> +}
>  
>  /*
>   * Section 10.1 Smart Battery
> @@ -5896,6 +6175,13 @@ static fwts_framework_minor_test method_tests[] = {
>  	{ method_test_TIP, "Test _TIP (Expired Timer Wake Policy)." },
>  	{ method_test_TIV, "Test _TIV (Timer Values)." },
>  
> +	/* Section 9.20 NVDIMM Devices */
> +	{ method_test_NBS, "Test _NBS (NVDIMM Boot Status)." },
> +	{ method_test_NCH, "Test _NCH (NVDIMM Current Health Information)." },
> +	{ method_test_NIC, "Test _NIC (NVDIMM Health Error Injection Capabilities)." },
> +	{ method_test_NIH, "Test _NIH (NVDIMM Inject/Clear Health Errors)." },
> +	{ method_test_NIG, "Test _NIG (NVDIMM Inject Health Error Status)." },
> +
>  	/* Section 10.1 Smart Battery */
>  
>  	{ method_test_SBS, "Test _SBS (Smart Battery Subsystem)." },
> diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h
> index 4a7c5ed9..565af728 100644
> --- a/src/lib/include/fwts_acpi_object_eval.h
> +++ b/src/lib/include/fwts_acpi_object_eval.h
> @@ -66,6 +66,46 @@ typedef struct {
>  	uint8_t		pad2[3];
>  } __attribute__ ((packed)) fwts_acpi_time_buffer;
>  
> +/* Returns for NVDIMM control methods */
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	health_status_flags;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[50];
> +}  __attribute__ ((packed)) nch_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	data_loss_count;
> +	uint8_t		reserved[54];
> +}  __attribute__ ((packed)) nbs_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint32_t	health_error_injection;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[52];
> +}  __attribute__ ((packed)) nic_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +}  __attribute__ ((packed)) nih_return_t;
> +
> +typedef struct {
> +	uint16_t	status;
> +	uint16_t	extended_status;
> +	uint16_t	validation_flags;
> +	uint32_t	health_status_errors;
> +	uint32_t	health_status_attributes;
> +	uint8_t		reserved[50];
> +}  __attribute__ ((packed)) nig_return_t;
> +
>  #define fwts_method_check_type(fw, name, buf, type) 			\
>  	fwts_method_check_type__(fw, name, buf, type, #type)
>
ivanhu Feb. 18, 2019, 3:35 p.m. | #3
On 2/18/19 6:09 PM, ivanhu wrote:
> On 2/12/19 1:42 PM, Alex Hung wrote:
>> Signed-off-by: Alex Hung <alex.hung@canonical.com>
>> ---
>>  src/acpi/method/method.c                | 286 ++++++++++++++++++++++++
>>  src/lib/include/fwts_acpi_object_eval.h |  40 ++++
>>  2 files changed, 326 insertions(+)
>>
>> diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c
>> index 654112d9..48a5c039 100644
>> --- a/src/acpi/method/method.c
>> +++ b/src/acpi/method/method.c
>> @@ -138,6 +138,11 @@
>>   * _MSG 	 Y
>>   * _MSM 	 N
>>   * _MTL 	 Y
>> + * _NBS 	 Y
>> + * _NCH 	 Y
>> + * _NIC 	 Y
>> + * _NIH 	 Y
>> + * _NIG 	 Y
>>   * _NTT 	 Y
>>   * _OFF 	 Y
>>   * _ON_ 	 Y
>> @@ -3574,6 +3579,280 @@ static int method_test_TIV(fwts_framework *fw)
>>  		"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
>>  }
>>  
>> +/*
>> + * Section 9.20 NVDIMM Devices
>> + */
>> +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_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 (obj->Buffer.Length != 64) {
>> +		failed = true;
>> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
>> +			"Method_NBSBadBufferSize",
>> +			"%s should return a buffer of 64 bytes, but "
>> +			"instead just returned %" PRIu32,
>> +			name, obj->Buffer.Length);
>> +	}
>> +
>> +	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);
> Should check the rest return bytes are reserved?
>> +
>> +	if (!failed)
>> +		fwts_method_passed_sane(fw, name, "buffer");
>> +}
>> +
>> +static int method_test_NBS(fwts_framework *fw)
>> +{
>> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
>> +		"_NBS", NULL, 0, method_test_NBS_return, NULL);
>> +}
>> +
>> +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 (obj->Buffer.Length != 64) {
>> +		failed = true;
>> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
>> +			"Method_NCHBadBufferSize",
>> +			"%s should return a buffer of 64 bytes, but "
>> +			"instead just returned %" PRIu32,
>> +			name, obj->Buffer.Length);
>> +	}
>> +
>> +	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);
>> +
> Should check the rest return bytes are reserved?
>> +	if (!failed)
>> +		fwts_method_passed_sane(fw, name, "buffer");
>> +}
>> +
>> +static int method_test_NCH(fwts_framework *fw)
>> +{
>> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
>> +		"_NCH", NULL, 0, method_test_NCH_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 (obj->Buffer.Length != 64) {
>> +		failed = true;
>> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
>> +			"Method_NICBadBufferSize",
>> +			"%s should return a buffer of 64 bytes, but "
>> +			"instead just returned %" PRIu32,
>> +			name, obj->Buffer.Length);
>> +	}
>> +
>> +	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);
> same here.
>> +
>> +	if (!failed)
>> +		fwts_method_passed_sane(fw, name, "buffer");
>> +}
>> +
>> +static int method_test_NIC(fwts_framework *fw)
>> +{
>> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
>> +		"_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 (obj->Buffer.Length != 64) {
>> +		failed = true;
>> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
>> +			"Method_NIHBadBufferSize",
>> +			"%s should return a buffer of 64 bytes, but "
>> +			"instead just returned %" PRIu32,
>> +			name, obj->Buffer.Length);
>> +	}
>> +
>> +	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)
>> +{
>> +	ACPI_OBJECT arg0;
>> +	char data[64];
>> +	int result;
>> +	int i, j;
>> +
>> +	memset(data, 0, sizeof(data));
>> +	arg0.Type = ACPI_TYPE_BUFFER;
>> +	arg0.Buffer.Length = 64;
>> +	arg0.Buffer.Pointer = (void *)data;
>> +
>> +	/* not permanent (j = 0) and permanent (j = 1) errors  */
>> +	for (j = 0; j <= 1; j++) {
>> +		/* inject (i = 1) and clear (i = 2) errors */
>> +		for (i = 1; i <= 2; i++) {
>> +			data[0] = i;
>> +			data[4] = 3;
>> +			data[5] = 7;
>> +			data[6] = 7;
>> +			data[8] = j;
>> +
>> +			result = method_evaluate_method(fw, METHOD_OPTIONAL,
>> +				"_NIH", &arg0, 1, method_test_NIH_return, NULL);
>> +
>> +			if (result != FWTS_OK)
>> +				return result;
>> +		}
>> +	}
>> +
>> +	return FWTS_OK;
>> +}
>> +
>> +static void method_test_NIG_return(
>> +	fwts_framework *fw,
>> +	char *name,
>> +	ACPI_BUFFER *buf,
>> +	ACPI_OBJECT *obj,
>> +	void *private)
>> +{
>> +	bool failed = false;
>> +	nig_return_t *ret;
>> +
>> +	FWTS_UNUSED(private);
>> +
>> +	if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
>> +		return;
>> +
>> +	if (obj->Buffer.Length != 64) {
>> +		failed = true;
>> +		fwts_failed(fw, LOG_LEVEL_CRITICAL,
>> +			"Method_NIGBadBufferSize",
>> +			"%s should return a buffer of 64 bytes, but "
>> +			"instead just returned %" PRIu32,
>> +			name, obj->Buffer.Length);
>> +	}
>> +
>> +	ret = (nig_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, "_NIG", "Validation Flags", ret->validation_flags, sizeof(uint16_t), 2, 15, &failed);
>> +
>> +	/* Injected Health Status Errors [2..7], [11.15], [19..31] are reserved */
>> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 2, 7, &failed);
>> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 11, 15, &failed);
>> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 19, 31, &failed);
>> +
>> +	fwts_acpi_reserved_bits_check(fw, "_NIG", "Health Status Attributes of Injected Errors", ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed);
>> +
> same here.
>> +	if (!failed)
>> +		fwts_method_passed_sane(fw, name, "buffer");
>> +}
>> +
>> +static int method_test_NIG(fwts_framework *fw)
>> +{
>> +	return method_evaluate_method(fw, METHOD_OPTIONAL,
>> +		"_NIG", NULL, 0, method_test_NIG_return, NULL);
>> +}
>>  
>>  /*
>>   * Section 10.1 Smart Battery
>> @@ -5896,6 +6175,13 @@ static fwts_framework_minor_test method_tests[] = {
>>  	{ method_test_TIP, "Test _TIP (Expired Timer Wake Policy)." },
>>  	{ method_test_TIV, "Test _TIV (Timer Values)." },
>>  
>> +	/* Section 9.20 NVDIMM Devices */
>> +	{ method_test_NBS, "Test _NBS (NVDIMM Boot Status)." },
>> +	{ method_test_NCH, "Test _NCH (NVDIMM Current Health Information)." },
>> +	{ method_test_NIC, "Test _NIC (NVDIMM Health Error Injection Capabilities)." },
>> +	{ method_test_NIH, "Test _NIH (NVDIMM Inject/Clear Health Errors)." },
>> +	{ method_test_NIG, "Test _NIG (NVDIMM Inject Health Error Status)." },
>> +
>>  	/* Section 10.1 Smart Battery */
>>  
>>  	{ method_test_SBS, "Test _SBS (Smart Battery Subsystem)." },
>> diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h
>> index 4a7c5ed9..565af728 100644
>> --- a/src/lib/include/fwts_acpi_object_eval.h
>> +++ b/src/lib/include/fwts_acpi_object_eval.h
>> @@ -66,6 +66,46 @@ typedef struct {
>>  	uint8_t		pad2[3];
>>  } __attribute__ ((packed)) fwts_acpi_time_buffer;
>>  
>> +/* Returns for NVDIMM control methods */
>> +typedef struct {
>> +	uint16_t	status;
>> +	uint16_t	extended_status;
>> +	uint16_t	validation_flags;
>> +	uint32_t	health_status_flags;
>> +	uint32_t	health_status_attributes;
>> +	uint8_t		reserved[50];
>> +}  __attribute__ ((packed)) nch_return_t;
>> +
>> +typedef struct {
>> +	uint16_t	status;
>> +	uint16_t	extended_status;
>> +	uint16_t	validation_flags;
>> +	uint32_t	data_loss_count;
>> +	uint8_t		reserved[54];
>> +}  __attribute__ ((packed)) nbs_return_t;
>> +
>> +typedef struct {
>> +	uint16_t	status;
>> +	uint16_t	extended_status;
>> +	uint32_t	health_error_injection;
>> +	uint32_t	health_status_attributes;
>> +	uint8_t		reserved[52];
>> +}  __attribute__ ((packed)) nic_return_t;
>> +
>> +typedef struct {
>> +	uint16_t	status;
>> +	uint16_t	extended_status;
>> +}  __attribute__ ((packed)) nih_return_t;
>> +
>> +typedef struct {
>> +	uint16_t	status;
>> +	uint16_t	extended_status;
>> +	uint16_t	validation_flags;
>> +	uint32_t	health_status_errors;
>> +	uint32_t	health_status_attributes;
>> +	uint8_t		reserved[50];
>> +}  __attribute__ ((packed)) nig_return_t;
>> +
>>  #define fwts_method_check_type(fw, name, buf, type) 			\
>>  	fwts_method_check_type__(fw, name, buf, type, #type)

Ack this patch first, can do the reserved return size on next patch.

Acked-by: Ivan Hu <ivan.hu@canonical.com>

Patch

diff --git a/src/acpi/method/method.c b/src/acpi/method/method.c
index 654112d9..48a5c039 100644
--- a/src/acpi/method/method.c
+++ b/src/acpi/method/method.c
@@ -138,6 +138,11 @@ 
  * _MSG 	 Y
  * _MSM 	 N
  * _MTL 	 Y
+ * _NBS 	 Y
+ * _NCH 	 Y
+ * _NIC 	 Y
+ * _NIH 	 Y
+ * _NIG 	 Y
  * _NTT 	 Y
  * _OFF 	 Y
  * _ON_ 	 Y
@@ -3574,6 +3579,280 @@  static int method_test_TIV(fwts_framework *fw)
 		"_TIV", arg, 1, fwts_method_test_integer_return, NULL);
 }
 
+/*
+ * Section 9.20 NVDIMM Devices
+ */
+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_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 (obj->Buffer.Length != 64) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"Method_NBSBadBufferSize",
+			"%s should return a buffer of 64 bytes, but "
+			"instead just returned %" PRIu32,
+			name, obj->Buffer.Length);
+	}
+
+	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 method_evaluate_method(fw, METHOD_OPTIONAL,
+		"_NBS", NULL, 0, method_test_NBS_return, NULL);
+}
+
+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 (obj->Buffer.Length != 64) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"Method_NCHBadBufferSize",
+			"%s should return a buffer of 64 bytes, but "
+			"instead just returned %" PRIu32,
+			name, obj->Buffer.Length);
+	}
+
+	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 method_evaluate_method(fw, METHOD_OPTIONAL,
+		"_NCH", NULL, 0, method_test_NCH_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 (obj->Buffer.Length != 64) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"Method_NICBadBufferSize",
+			"%s should return a buffer of 64 bytes, but "
+			"instead just returned %" PRIu32,
+			name, obj->Buffer.Length);
+	}
+
+	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 method_evaluate_method(fw, METHOD_OPTIONAL,
+		"_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 (obj->Buffer.Length != 64) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"Method_NIHBadBufferSize",
+			"%s should return a buffer of 64 bytes, but "
+			"instead just returned %" PRIu32,
+			name, obj->Buffer.Length);
+	}
+
+	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)
+{
+	ACPI_OBJECT arg0;
+	char data[64];
+	int result;
+	int i, j;
+
+	memset(data, 0, sizeof(data));
+	arg0.Type = ACPI_TYPE_BUFFER;
+	arg0.Buffer.Length = 64;
+	arg0.Buffer.Pointer = (void *)data;
+
+	/* not permanent (j = 0) and permanent (j = 1) errors  */
+	for (j = 0; j <= 1; j++) {
+		/* inject (i = 1) and clear (i = 2) errors */
+		for (i = 1; i <= 2; i++) {
+			data[0] = i;
+			data[4] = 3;
+			data[5] = 7;
+			data[6] = 7;
+			data[8] = j;
+
+			result = method_evaluate_method(fw, METHOD_OPTIONAL,
+				"_NIH", &arg0, 1, method_test_NIH_return, NULL);
+
+			if (result != FWTS_OK)
+				return result;
+		}
+	}
+
+	return FWTS_OK;
+}
+
+static void method_test_NIG_return(
+	fwts_framework *fw,
+	char *name,
+	ACPI_BUFFER *buf,
+	ACPI_OBJECT *obj,
+	void *private)
+{
+	bool failed = false;
+	nig_return_t *ret;
+
+	FWTS_UNUSED(private);
+
+	if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_BUFFER) != FWTS_OK)
+		return;
+
+	if (obj->Buffer.Length != 64) {
+		failed = true;
+		fwts_failed(fw, LOG_LEVEL_CRITICAL,
+			"Method_NIGBadBufferSize",
+			"%s should return a buffer of 64 bytes, but "
+			"instead just returned %" PRIu32,
+			name, obj->Buffer.Length);
+	}
+
+	ret = (nig_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, "_NIG", "Validation Flags", ret->validation_flags, sizeof(uint16_t), 2, 15, &failed);
+
+	/* Injected Health Status Errors [2..7], [11.15], [19..31] are reserved */
+	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 2, 7, &failed);
+	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 11, 15, &failed);
+	fwts_acpi_reserved_bits_check(fw, "_NIG", "Injected Health Status Errors", ret->health_status_errors, sizeof(uint32_t), 19, 31, &failed);
+
+	fwts_acpi_reserved_bits_check(fw, "_NIG", "Health Status Attributes of Injected Errors", ret->health_status_attributes, sizeof(uint32_t), 1, 31, &failed);
+
+	if (!failed)
+		fwts_method_passed_sane(fw, name, "buffer");
+}
+
+static int method_test_NIG(fwts_framework *fw)
+{
+	return method_evaluate_method(fw, METHOD_OPTIONAL,
+		"_NIG", NULL, 0, method_test_NIG_return, NULL);
+}
 
 /*
  * Section 10.1 Smart Battery
@@ -5896,6 +6175,13 @@  static fwts_framework_minor_test method_tests[] = {
 	{ method_test_TIP, "Test _TIP (Expired Timer Wake Policy)." },
 	{ method_test_TIV, "Test _TIV (Timer Values)." },
 
+	/* Section 9.20 NVDIMM Devices */
+	{ method_test_NBS, "Test _NBS (NVDIMM Boot Status)." },
+	{ method_test_NCH, "Test _NCH (NVDIMM Current Health Information)." },
+	{ method_test_NIC, "Test _NIC (NVDIMM Health Error Injection Capabilities)." },
+	{ method_test_NIH, "Test _NIH (NVDIMM Inject/Clear Health Errors)." },
+	{ method_test_NIG, "Test _NIG (NVDIMM Inject Health Error Status)." },
+
 	/* Section 10.1 Smart Battery */
 
 	{ method_test_SBS, "Test _SBS (Smart Battery Subsystem)." },
diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h
index 4a7c5ed9..565af728 100644
--- a/src/lib/include/fwts_acpi_object_eval.h
+++ b/src/lib/include/fwts_acpi_object_eval.h
@@ -66,6 +66,46 @@  typedef struct {
 	uint8_t		pad2[3];
 } __attribute__ ((packed)) fwts_acpi_time_buffer;
 
+/* Returns for NVDIMM control methods */
+typedef struct {
+	uint16_t	status;
+	uint16_t	extended_status;
+	uint16_t	validation_flags;
+	uint32_t	health_status_flags;
+	uint32_t	health_status_attributes;
+	uint8_t		reserved[50];
+}  __attribute__ ((packed)) nch_return_t;
+
+typedef struct {
+	uint16_t	status;
+	uint16_t	extended_status;
+	uint16_t	validation_flags;
+	uint32_t	data_loss_count;
+	uint8_t		reserved[54];
+}  __attribute__ ((packed)) nbs_return_t;
+
+typedef struct {
+	uint16_t	status;
+	uint16_t	extended_status;
+	uint32_t	health_error_injection;
+	uint32_t	health_status_attributes;
+	uint8_t		reserved[52];
+}  __attribute__ ((packed)) nic_return_t;
+
+typedef struct {
+	uint16_t	status;
+	uint16_t	extended_status;
+}  __attribute__ ((packed)) nih_return_t;
+
+typedef struct {
+	uint16_t	status;
+	uint16_t	extended_status;
+	uint16_t	validation_flags;
+	uint32_t	health_status_errors;
+	uint32_t	health_status_attributes;
+	uint8_t		reserved[50];
+}  __attribute__ ((packed)) nig_return_t;
+
 #define fwts_method_check_type(fw, name, buf, type) 			\
 	fwts_method_check_type__(fw, name, buf, type, #type)