Message ID | 1506663203-24038-2-git-send-email-alex.hung@canonical.com |
---|---|
State | Accepted |
Headers | show |
Series | [1/2] lib: move and rename helper functions from method.c | expand |
On 29/09/17 06:33, Alex Hung wrote: > This type of tests provides flexibility to test control methods under ACPI > devices, such as methods that are not required by OS but are mandatory > by ACPI devices. > > Signed-off-by: Alex Hung <alex.hung@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/devices/ac_adapter/ac.c | 204 ++++++++++++++++++++++++++++++++ > src/lib/include/fwts_acpi_object_eval.h | 3 + > src/lib/src/fwts_acpi_object_eval.c | 76 ++++++++++++ > 4 files changed, 284 insertions(+) > create mode 100644 src/acpi/devices/ac_adapter/ac.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 6e28718..357d12b 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -45,6 +45,7 @@ endif > # > fwts_SOURCES = main.c \ > acpi/ac_adapter/ac_adapter.c \ > + acpi/devices/ac_adapter/ac.c \ > acpi/acpidump/acpidump.c \ > acpi/acpiinfo/acpiinfo.c \ > acpi/acpitables/acpitables.c \ > diff --git a/src/acpi/devices/ac_adapter/ac.c b/src/acpi/devices/ac_adapter/ac.c > new file mode 100644 > index 0000000..d82b303 > --- /dev/null > +++ b/src/acpi/devices/ac_adapter/ac.c > @@ -0,0 +1,204 @@ > +/* > + * Copyright (C) 2017 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 <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > + > +#define FWTS_ACPI_AC_HID "ACPI0003" > + > +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_ac_init(fwts_framework *fw) > +{ > + ACPI_STATUS status; > + > + if (fwts_acpica_init(fw) != FWTS_OK) > + return FWTS_ERROR; > + > + status = AcpiGetDevices(FWTS_ACPI_AC_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 AC device does not exist, skipping test"); > + return FWTS_SKIP; > + } > + > + return FWTS_OK; > +} > + > +static void method_test_PSR_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK) > + return; > + > + if (obj->Integer.Value > 2) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "Method_PSRZeroOrOne", > + "%s returned 0x%8.8" PRIx64 ", expected 0 " > + "(offline) or 1 (online)", > + name, (uint64_t)obj->Integer.Value); > + } else > + fwts_method_passed_sane_uint64(fw, name, obj->Integer.Value); > +} > + > +static int method_test_PSR(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PSR", NULL, 0, method_test_PSR_return, NULL); > +} > + > +static void method_test_PCL_return(fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PCL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count); > +} > + > +static int method_test_PCL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PCL", NULL, 0, method_test_PCL_return, NULL); > +} > + > +static void method_test_PIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + static const fwts_package_element elements[] = { > + { ACPI_TYPE_INTEGER, "Power Source State" }, > + { ACPI_TYPE_INTEGER, "Maximum Output Power" }, > + { ACPI_TYPE_INTEGER, "Maximum Input Power" }, > + { ACPI_TYPE_STRING, "Model Number" }, > + { ACPI_TYPE_STRING, "Serial Number" }, > + { ACPI_TYPE_STRING, "OEM Information" } > + }; > + > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_count_equal(fw, name, "_PIF", obj, 6) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_type(fw, name, "_PIF", obj, elements, 6) != FWTS_OK) > + return; > + > + fwts_acpi_object_dump(fw, obj); > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PIF(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PIF", NULL, 0, method_test_PIF_return, NULL); > +} > + > +static void method_test_PRL_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PRL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PRL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PRL", NULL, 0, method_test_PRL_return, NULL); > +} > + > +static fwts_framework_minor_test acpi_ac_tests[] = { > + { method_test_PSR, "Test _PSR (Power Source)." }, > + { method_test_PCL, "Test _PCL (Power Consumer List)." }, > + { method_test_PIF, "Test _PIF (Power Source Information)." }, > + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." }, > + { NULL, NULL } > +}; > + > +static int acpi_ac_deinit(fwts_framework *fw) > +{ > + FWTS_UNUSED(fw); > + fwts_acpica_deinit(); > + > + return FWTS_OK; > +} > + > +static fwts_framework_ops acpi_ac_ops = { > + .description = "AC adapter device test", > + .init = acpi_ac_init, > + .deinit = acpi_ac_deinit, > + .minor_tests = acpi_ac_tests > +}; > + > +FWTS_REGISTER("acpi_ac", &acpi_ac_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI) > + > +#endif > diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h > index 211be4a..41a5b6a 100644 > --- a/src/lib/include/fwts_acpi_object_eval.h > +++ b/src/lib/include/fwts_acpi_object_eval.h > @@ -72,4 +72,7 @@ void fwts_method_test_NULL_return(fwts_framework *fw, char *name, ACPI_BUFFER *b > void fwts_method_test_passed_failed_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > void fwts_method_test_polling_return( fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > > +void fwts_evaluate_found_method(fwts_framework *fw, ACPI_HANDLE *parent, char *name, fwts_method_return check_func, void *private, ACPI_OBJECT_LIST *arg_list); > +int fwts_evaluate_method(fwts_framework *fw, uint32_t test_type, ACPI_HANDLE *parent, char *name, ACPI_OBJECT *args, uint32_t num_args, fwts_method_return check_func, void *private); > + > #endif > diff --git a/src/lib/src/fwts_acpi_object_eval.c b/src/lib/src/fwts_acpi_object_eval.c > index d8d3292..f2f32a4 100644 > --- a/src/lib/src/fwts_acpi_object_eval.c > +++ b/src/lib/src/fwts_acpi_object_eval.c > @@ -833,4 +833,80 @@ void fwts_method_test_polling_return( > } > } > > +void fwts_evaluate_found_method( > + fwts_framework *fw, > + ACPI_HANDLE *parent, > + char *name, > + fwts_method_return check_func, > + void *private, > + ACPI_OBJECT_LIST *arg_list) > +{ > + ACPI_BUFFER buf; > + ACPI_STATUS status; > + int sem_acquired; > + int sem_released; > + > + fwts_acpica_sem_count_clear(); > + > + buf.Length = ACPI_ALLOCATE_BUFFER; > + buf.Pointer = NULL; > + status = AcpiEvaluateObject(*parent, name, arg_list, &buf); > + > + if (ACPI_SUCCESS(status) && check_func != NULL) { > + ACPI_OBJECT *obj = buf.Pointer; > + check_func(fw, name, &buf, obj, private); > + } > + free(buf.Pointer); > + > + fwts_acpica_sem_count_get(&sem_acquired, &sem_released); > + if (sem_acquired != sem_released) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired", > + "%s left %d locks in an acquired state.", > + name, sem_acquired - sem_released); > + fwts_advice(fw, > + "Locks left in an acquired state generally indicates " > + "that the AML code is not releasing a lock. This can " > + "sometimes occur when a method hits an error " > + "condition and exits prematurely without releasing an " > + "acquired lock. It may be occurring in the method " > + "being tested or other methods used while evaluating " > + "the method."); > + } > +} > + > +int fwts_evaluate_method(fwts_framework *fw, > + uint32_t test_type, /* Manditory or optional */ > + ACPI_HANDLE *parent, > + char *name, > + ACPI_OBJECT *args, > + uint32_t num_args, > + fwts_method_return check_func, > + void *private) > +{ > + ACPI_OBJECT_LIST arg_list; > + ACPI_HANDLE method; > + ACPI_STATUS status; > + > + status = AcpiGetHandle (*parent, name, &method); > + if (ACPI_SUCCESS(status)) { > + arg_list.Count = num_args; > + arg_list.Pointer = args; > + fwts_evaluate_found_method(fw, parent, name, check_func, private, &arg_list); > + } > + > + if (status == AE_NOT_FOUND && !(test_type & METHOD_SILENT)) { > + if (test_type & METHOD_MANDATORY) { > + fwts_failed(fw, LOG_LEVEL_CRITICAL, "MethodNotExist", "Object %s did not exist.", name); > + return FWTS_ERROR; > + } > + > + if (test_type & METHOD_OPTIONAL) { > + fwts_skipped(fw, "Skipping test for non-existent object %s.", name); > + return FWTS_SKIP; > + } > + } > + > + return FWTS_OK; > +} > + > #endif > Acked-by: Colin Ian King <colin.king@canonical.com>
Hi Alex, Those APCI methods(_PCL, _PSR, _PCL, _PIF) have been tested on fwts method tests, why is it necessary to collect and test again for specific devices? And is that possible that we create a single device.c to list all specific devices with the tested acpi methods which would like to be added? such as acadapter = [_PCL, _PSR, _PCL, _PIF] battery = [_BIF, _BIX, _BMA, _BMS, ...] smart battery = [......] instead of adding so many specific device tests and c files. It may be easier to maintain and we can run like "fwts devices" to test all specific ACPI devices. Cheers, Ivan On 09/29/2017 01:33 PM, Alex Hung wrote: > This type of tests provides flexibility to test control methods under ACPI > devices, such as methods that are not required by OS but are mandatory > by ACPI devices. > > Signed-off-by: Alex Hung <alex.hung@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/devices/ac_adapter/ac.c | 204 ++++++++++++++++++++++++++++++++ > src/lib/include/fwts_acpi_object_eval.h | 3 + > src/lib/src/fwts_acpi_object_eval.c | 76 ++++++++++++ > 4 files changed, 284 insertions(+) > create mode 100644 src/acpi/devices/ac_adapter/ac.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 6e28718..357d12b 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -45,6 +45,7 @@ endif > # > fwts_SOURCES = main.c \ > acpi/ac_adapter/ac_adapter.c \ > + acpi/devices/ac_adapter/ac.c \ > acpi/acpidump/acpidump.c \ > acpi/acpiinfo/acpiinfo.c \ > acpi/acpitables/acpitables.c \ > diff --git a/src/acpi/devices/ac_adapter/ac.c b/src/acpi/devices/ac_adapter/ac.c > new file mode 100644 > index 0000000..d82b303 > --- /dev/null > +++ b/src/acpi/devices/ac_adapter/ac.c > @@ -0,0 +1,204 @@ > +/* > + * Copyright (C) 2017 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 <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > + > +#define FWTS_ACPI_AC_HID "ACPI0003" > + > +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_ac_init(fwts_framework *fw) > +{ > + ACPI_STATUS status; > + > + if (fwts_acpica_init(fw) != FWTS_OK) > + return FWTS_ERROR; > + > + status = AcpiGetDevices(FWTS_ACPI_AC_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 AC device does not exist, skipping test"); > + return FWTS_SKIP; > + } > + > + return FWTS_OK; > +} > + > +static void method_test_PSR_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK) > + return; > + > + if (obj->Integer.Value > 2) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "Method_PSRZeroOrOne", > + "%s returned 0x%8.8" PRIx64 ", expected 0 " > + "(offline) or 1 (online)", > + name, (uint64_t)obj->Integer.Value); > + } else > + fwts_method_passed_sane_uint64(fw, name, obj->Integer.Value); > +} > + > +static int method_test_PSR(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PSR", NULL, 0, method_test_PSR_return, NULL); > +} > + > +static void method_test_PCL_return(fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PCL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count); > +} > + > +static int method_test_PCL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PCL", NULL, 0, method_test_PCL_return, NULL); > +} > + > +static void method_test_PIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + static const fwts_package_element elements[] = { > + { ACPI_TYPE_INTEGER, "Power Source State" }, > + { ACPI_TYPE_INTEGER, "Maximum Output Power" }, > + { ACPI_TYPE_INTEGER, "Maximum Input Power" }, > + { ACPI_TYPE_STRING, "Model Number" }, > + { ACPI_TYPE_STRING, "Serial Number" }, > + { ACPI_TYPE_STRING, "OEM Information" } > + }; > + > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_count_equal(fw, name, "_PIF", obj, 6) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_type(fw, name, "_PIF", obj, elements, 6) != FWTS_OK) > + return; > + > + fwts_acpi_object_dump(fw, obj); > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PIF(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PIF", NULL, 0, method_test_PIF_return, NULL); > +} > + > +static void method_test_PRL_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PRL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PRL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PRL", NULL, 0, method_test_PRL_return, NULL); > +} > + > +static fwts_framework_minor_test acpi_ac_tests[] = { > + { method_test_PSR, "Test _PSR (Power Source)." }, > + { method_test_PCL, "Test _PCL (Power Consumer List)." }, > + { method_test_PIF, "Test _PIF (Power Source Information)." }, > + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." }, > + { NULL, NULL } > +}; > + > +static int acpi_ac_deinit(fwts_framework *fw) > +{ > + FWTS_UNUSED(fw); > + fwts_acpica_deinit(); > + > + return FWTS_OK; > +} > + > +static fwts_framework_ops acpi_ac_ops = { > + .description = "AC adapter device test", > + .init = acpi_ac_init, > + .deinit = acpi_ac_deinit, > + .minor_tests = acpi_ac_tests > +}; > + > +FWTS_REGISTER("acpi_ac", &acpi_ac_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI) > + > +#endif > diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h > index 211be4a..41a5b6a 100644 > --- a/src/lib/include/fwts_acpi_object_eval.h > +++ b/src/lib/include/fwts_acpi_object_eval.h > @@ -72,4 +72,7 @@ void fwts_method_test_NULL_return(fwts_framework *fw, char *name, ACPI_BUFFER *b > void fwts_method_test_passed_failed_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > void fwts_method_test_polling_return( fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > > +void fwts_evaluate_found_method(fwts_framework *fw, ACPI_HANDLE *parent, char *name, fwts_method_return check_func, void *private, ACPI_OBJECT_LIST *arg_list); > +int fwts_evaluate_method(fwts_framework *fw, uint32_t test_type, ACPI_HANDLE *parent, char *name, ACPI_OBJECT *args, uint32_t num_args, fwts_method_return check_func, void *private); > + > #endif > diff --git a/src/lib/src/fwts_acpi_object_eval.c b/src/lib/src/fwts_acpi_object_eval.c > index d8d3292..f2f32a4 100644 > --- a/src/lib/src/fwts_acpi_object_eval.c > +++ b/src/lib/src/fwts_acpi_object_eval.c > @@ -833,4 +833,80 @@ void fwts_method_test_polling_return( > } > } > > +void fwts_evaluate_found_method( > + fwts_framework *fw, > + ACPI_HANDLE *parent, > + char *name, > + fwts_method_return check_func, > + void *private, > + ACPI_OBJECT_LIST *arg_list) > +{ > + ACPI_BUFFER buf; > + ACPI_STATUS status; > + int sem_acquired; > + int sem_released; > + > + fwts_acpica_sem_count_clear(); > + > + buf.Length = ACPI_ALLOCATE_BUFFER; > + buf.Pointer = NULL; > + status = AcpiEvaluateObject(*parent, name, arg_list, &buf); > + > + if (ACPI_SUCCESS(status) && check_func != NULL) { > + ACPI_OBJECT *obj = buf.Pointer; > + check_func(fw, name, &buf, obj, private); > + } > + free(buf.Pointer); > + > + fwts_acpica_sem_count_get(&sem_acquired, &sem_released); > + if (sem_acquired != sem_released) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired", > + "%s left %d locks in an acquired state.", > + name, sem_acquired - sem_released); > + fwts_advice(fw, > + "Locks left in an acquired state generally indicates " > + "that the AML code is not releasing a lock. This can " > + "sometimes occur when a method hits an error " > + "condition and exits prematurely without releasing an " > + "acquired lock. It may be occurring in the method " > + "being tested or other methods used while evaluating " > + "the method."); > + } > +} > + > +int fwts_evaluate_method(fwts_framework *fw, > + uint32_t test_type, /* Manditory or optional */ > + ACPI_HANDLE *parent, > + char *name, > + ACPI_OBJECT *args, > + uint32_t num_args, > + fwts_method_return check_func, > + void *private) > +{ > + ACPI_OBJECT_LIST arg_list; > + ACPI_HANDLE method; > + ACPI_STATUS status; > + > + status = AcpiGetHandle (*parent, name, &method); > + if (ACPI_SUCCESS(status)) { > + arg_list.Count = num_args; > + arg_list.Pointer = args; > + fwts_evaluate_found_method(fw, parent, name, check_func, private, &arg_list); > + } > + > + if (status == AE_NOT_FOUND && !(test_type & METHOD_SILENT)) { > + if (test_type & METHOD_MANDATORY) { > + fwts_failed(fw, LOG_LEVEL_CRITICAL, "MethodNotExist", "Object %s did not exist.", name); > + return FWTS_ERROR; > + } > + > + if (test_type & METHOD_OPTIONAL) { > + fwts_skipped(fw, "Skipping test for non-existent object %s.", name); > + return FWTS_SKIP; > + } > + } > + > + return FWTS_OK; > +} > + > #endif >
Hi Ivan, The tests are more than testing the control methods but also testing whether specific methods are present under the devices. On Fri, Oct 6, 2017 at 1:26 AM, ivanhu <ivan.hu@canonical.com> wrote: > Hi Alex, > > Those APCI methods(_PCL, _PSR, _PCL, _PIF) have been tested on fwts method > tests, why is it necessary to collect and test again for specific devices? > > And is that possible that we create a single device.c to list all specific > devices with the tested acpi methods which would like to be added? such as > > acadapter = [_PCL, _PSR, _PCL, _PIF] > battery = [_BIF, _BIX, _BMA, _BMS, ...] > smart battery = [......] > > instead of adding so many specific device tests and c files. It may be > easier to maintain and we can run like "fwts devices" to test all specific > ACPI devices. > > Cheers, > Ivan > > > On 09/29/2017 01:33 PM, Alex Hung wrote: >> >> This type of tests provides flexibility to test control methods under ACPI >> devices, such as methods that are not required by OS but are mandatory >> by ACPI devices. >> >> Signed-off-by: Alex Hung <alex.hung@canonical.com> >> --- >> src/Makefile.am | 1 + >> src/acpi/devices/ac_adapter/ac.c | 204 >> ++++++++++++++++++++++++++++++++ >> src/lib/include/fwts_acpi_object_eval.h | 3 + >> src/lib/src/fwts_acpi_object_eval.c | 76 ++++++++++++ >> 4 files changed, 284 insertions(+) >> create mode 100644 src/acpi/devices/ac_adapter/ac.c >> >> diff --git a/src/Makefile.am b/src/Makefile.am >> index 6e28718..357d12b 100644 >> --- a/src/Makefile.am >> +++ b/src/Makefile.am >> @@ -45,6 +45,7 @@ endif >> # >> fwts_SOURCES = main.c \ >> acpi/ac_adapter/ac_adapter.c \ >> + acpi/devices/ac_adapter/ac.c \ >> acpi/acpidump/acpidump.c \ >> acpi/acpiinfo/acpiinfo.c \ >> acpi/acpitables/acpitables.c \ >> diff --git a/src/acpi/devices/ac_adapter/ac.c >> b/src/acpi/devices/ac_adapter/ac.c >> new file mode 100644 >> index 0000000..d82b303 >> --- /dev/null >> +++ b/src/acpi/devices/ac_adapter/ac.c >> @@ -0,0 +1,204 @@ >> +/* >> + * Copyright (C) 2017 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 <stdlib.h> >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <inttypes.h> >> +#include <string.h> >> + >> +#define FWTS_ACPI_AC_HID "ACPI0003" >> + >> +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_ac_init(fwts_framework *fw) >> +{ >> + ACPI_STATUS status; >> + >> + if (fwts_acpica_init(fw) != FWTS_OK) >> + return FWTS_ERROR; >> + >> + status = AcpiGetDevices(FWTS_ACPI_AC_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 AC device does not exist, >> skipping test"); >> + return FWTS_SKIP; >> + } >> + >> + return FWTS_OK; >> +} >> + >> +static void method_test_PSR_return( >> + fwts_framework *fw, >> + char *name, >> + ACPI_BUFFER *buf, >> + ACPI_OBJECT *obj, >> + void *private) >> +{ >> + FWTS_UNUSED(private); >> + >> + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != >> FWTS_OK) >> + return; >> + >> + if (obj->Integer.Value > 2) { >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, >> + "Method_PSRZeroOrOne", >> + "%s returned 0x%8.8" PRIx64 ", expected 0 " >> + "(offline) or 1 (online)", >> + name, (uint64_t)obj->Integer.Value); >> + } else >> + fwts_method_passed_sane_uint64(fw, name, >> obj->Integer.Value); >> +} >> + >> +static int method_test_PSR(fwts_framework *fw) >> +{ >> + return fwts_evaluate_method(fw, METHOD_MANDATORY, >> + &device, "_PSR", NULL, 0, method_test_PSR_return, NULL); >> +} >> + >> +static void method_test_PCL_return(fwts_framework *fw, >> + char *name, >> + ACPI_BUFFER *buf, >> + ACPI_OBJECT *obj, >> + void *private) >> +{ >> + FWTS_UNUSED(private); >> + >> + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != >> FWTS_OK) >> + return; >> + >> + if (fwts_method_package_elements_all_type(fw, name, "_PCL", obj, >> ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) >> + return; >> + >> + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " >> references.", name, obj->Package.Count); >> +} >> + >> +static int method_test_PCL(fwts_framework *fw) >> +{ >> + return fwts_evaluate_method(fw, METHOD_MANDATORY, >> + &device, "_PCL", NULL, 0, method_test_PCL_return, NULL); >> +} >> + >> +static void method_test_PIF_return( >> + fwts_framework *fw, >> + char *name, >> + ACPI_BUFFER *buf, >> + ACPI_OBJECT *obj, >> + void *private) >> +{ >> + static const fwts_package_element elements[] = { >> + { ACPI_TYPE_INTEGER, "Power Source State" }, >> + { ACPI_TYPE_INTEGER, "Maximum Output Power" }, >> + { ACPI_TYPE_INTEGER, "Maximum Input Power" }, >> + { ACPI_TYPE_STRING, "Model Number" }, >> + { ACPI_TYPE_STRING, "Serial Number" }, >> + { ACPI_TYPE_STRING, "OEM Information" } >> + }; >> + >> + FWTS_UNUSED(private); >> + >> + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != >> FWTS_OK) >> + return; >> + >> + if (fwts_method_package_count_equal(fw, name, "_PIF", obj, 6) != >> FWTS_OK) >> + return; >> + >> + if (fwts_method_package_elements_type(fw, name, "_PIF", obj, >> elements, 6) != FWTS_OK) >> + return; >> + >> + fwts_acpi_object_dump(fw, obj); >> + >> + fwts_method_passed_sane(fw, name, "package"); >> +} >> + >> +static int method_test_PIF(fwts_framework *fw) >> +{ >> + return fwts_evaluate_method(fw, METHOD_OPTIONAL, >> + &device, "_PIF", NULL, 0, method_test_PIF_return, NULL); >> +} >> + >> +static void method_test_PRL_return( >> + fwts_framework *fw, >> + char *name, >> + ACPI_BUFFER *buf, >> + ACPI_OBJECT *obj, >> + void *private) >> +{ >> + FWTS_UNUSED(private); >> + >> + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != >> FWTS_OK) >> + return; >> + >> + if (fwts_method_package_elements_all_type(fw, name, "_PRL", obj, >> ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) >> + return; >> + >> + fwts_method_passed_sane(fw, name, "package"); >> +} >> + >> +static int method_test_PRL(fwts_framework *fw) >> +{ >> + return fwts_evaluate_method(fw, METHOD_OPTIONAL, >> + &device, "_PRL", NULL, 0, method_test_PRL_return, NULL); >> +} >> + >> +static fwts_framework_minor_test acpi_ac_tests[] = { >> + { method_test_PSR, "Test _PSR (Power Source)." }, >> + { method_test_PCL, "Test _PCL (Power Consumer List)." }, >> + { method_test_PIF, "Test _PIF (Power Source Information)." }, >> + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." }, >> + { NULL, NULL } >> +}; >> + >> +static int acpi_ac_deinit(fwts_framework *fw) >> +{ >> + FWTS_UNUSED(fw); >> + fwts_acpica_deinit(); >> + >> + return FWTS_OK; >> +} >> + >> +static fwts_framework_ops acpi_ac_ops = { >> + .description = "AC adapter device test", >> + .init = acpi_ac_init, >> + .deinit = acpi_ac_deinit, >> + .minor_tests = acpi_ac_tests >> +}; >> + >> +FWTS_REGISTER("acpi_ac", &acpi_ac_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH >> | FWTS_FLAG_TEST_ACPI) >> + >> +#endif >> diff --git a/src/lib/include/fwts_acpi_object_eval.h >> b/src/lib/include/fwts_acpi_object_eval.h >> index 211be4a..41a5b6a 100644 >> --- a/src/lib/include/fwts_acpi_object_eval.h >> +++ b/src/lib/include/fwts_acpi_object_eval.h >> @@ -72,4 +72,7 @@ void fwts_method_test_NULL_return(fwts_framework *fw, >> char *name, ACPI_BUFFER *b >> void fwts_method_test_passed_failed_return(fwts_framework *fw, char >> *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); >> void fwts_method_test_polling_return( fwts_framework *fw, char *name, >> ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); >> +void fwts_evaluate_found_method(fwts_framework *fw, ACPI_HANDLE >> *parent, char *name, fwts_method_return check_func, void *private, >> ACPI_OBJECT_LIST *arg_list); >> +int fwts_evaluate_method(fwts_framework *fw, uint32_t test_type, >> ACPI_HANDLE *parent, char *name, ACPI_OBJECT *args, uint32_t num_args, >> fwts_method_return check_func, void *private); >> + >> #endif >> diff --git a/src/lib/src/fwts_acpi_object_eval.c >> b/src/lib/src/fwts_acpi_object_eval.c >> index d8d3292..f2f32a4 100644 >> --- a/src/lib/src/fwts_acpi_object_eval.c >> +++ b/src/lib/src/fwts_acpi_object_eval.c >> @@ -833,4 +833,80 @@ void fwts_method_test_polling_return( >> } >> } >> +void fwts_evaluate_found_method( >> + fwts_framework *fw, >> + ACPI_HANDLE *parent, >> + char *name, >> + fwts_method_return check_func, >> + void *private, >> + ACPI_OBJECT_LIST *arg_list) >> +{ >> + ACPI_BUFFER buf; >> + ACPI_STATUS status; >> + int sem_acquired; >> + int sem_released; >> + >> + fwts_acpica_sem_count_clear(); >> + >> + buf.Length = ACPI_ALLOCATE_BUFFER; >> + buf.Pointer = NULL; >> + status = AcpiEvaluateObject(*parent, name, arg_list, &buf); >> + >> + if (ACPI_SUCCESS(status) && check_func != NULL) { >> + ACPI_OBJECT *obj = buf.Pointer; >> + check_func(fw, name, &buf, obj, private); >> + } >> + free(buf.Pointer); >> + >> + fwts_acpica_sem_count_get(&sem_acquired, &sem_released); >> + if (sem_acquired != sem_released) { >> + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired", >> + "%s left %d locks in an acquired state.", >> + name, sem_acquired - sem_released); >> + fwts_advice(fw, >> + "Locks left in an acquired state generally >> indicates " >> + "that the AML code is not releasing a lock. This >> can " >> + "sometimes occur when a method hits an error " >> + "condition and exits prematurely without releasing >> an " >> + "acquired lock. It may be occurring in the method >> " >> + "being tested or other methods used while >> evaluating " >> + "the method."); >> + } >> +} >> + >> +int fwts_evaluate_method(fwts_framework *fw, >> + uint32_t test_type, /* Manditory or optional */ >> + ACPI_HANDLE *parent, >> + char *name, >> + ACPI_OBJECT *args, >> + uint32_t num_args, >> + fwts_method_return check_func, >> + void *private) >> +{ >> + ACPI_OBJECT_LIST arg_list; >> + ACPI_HANDLE method; >> + ACPI_STATUS status; >> + >> + status = AcpiGetHandle (*parent, name, &method); >> + if (ACPI_SUCCESS(status)) { >> + arg_list.Count = num_args; >> + arg_list.Pointer = args; >> + fwts_evaluate_found_method(fw, parent, name, check_func, >> private, &arg_list); >> + } >> + >> + if (status == AE_NOT_FOUND && !(test_type & METHOD_SILENT)) { >> + if (test_type & METHOD_MANDATORY) { >> + fwts_failed(fw, LOG_LEVEL_CRITICAL, >> "MethodNotExist", "Object %s did not exist.", name); >> + return FWTS_ERROR; >> + } >> + >> + if (test_type & METHOD_OPTIONAL) { >> + fwts_skipped(fw, "Skipping test for non-existent >> object %s.", name); >> + return FWTS_SKIP; >> + } >> + } >> + >> + return FWTS_OK; >> +} >> + >> #endif >> > > -- > fwts-devel mailing list > fwts-devel@lists.ubuntu.com > Modify settings or unsubscribe at: > https://lists.ubuntu.com/mailman/listinfo/fwts-devel
On 09/29/2017 01:33 PM, Alex Hung wrote: > This type of tests provides flexibility to test control methods under ACPI > devices, such as methods that are not required by OS but are mandatory > by ACPI devices. > > Signed-off-by: Alex Hung <alex.hung@canonical.com> > --- > src/Makefile.am | 1 + > src/acpi/devices/ac_adapter/ac.c | 204 ++++++++++++++++++++++++++++++++ > src/lib/include/fwts_acpi_object_eval.h | 3 + > src/lib/src/fwts_acpi_object_eval.c | 76 ++++++++++++ > 4 files changed, 284 insertions(+) > create mode 100644 src/acpi/devices/ac_adapter/ac.c > > diff --git a/src/Makefile.am b/src/Makefile.am > index 6e28718..357d12b 100644 > --- a/src/Makefile.am > +++ b/src/Makefile.am > @@ -45,6 +45,7 @@ endif > # > fwts_SOURCES = main.c \ > acpi/ac_adapter/ac_adapter.c \ > + acpi/devices/ac_adapter/ac.c \ > acpi/acpidump/acpidump.c \ > acpi/acpiinfo/acpiinfo.c \ > acpi/acpitables/acpitables.c \ > diff --git a/src/acpi/devices/ac_adapter/ac.c b/src/acpi/devices/ac_adapter/ac.c > new file mode 100644 > index 0000000..d82b303 > --- /dev/null > +++ b/src/acpi/devices/ac_adapter/ac.c > @@ -0,0 +1,204 @@ > +/* > + * Copyright (C) 2017 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 <stdlib.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <inttypes.h> > +#include <string.h> > + > +#define FWTS_ACPI_AC_HID "ACPI0003" > + > +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_ac_init(fwts_framework *fw) > +{ > + ACPI_STATUS status; > + > + if (fwts_acpica_init(fw) != FWTS_OK) > + return FWTS_ERROR; > + > + status = AcpiGetDevices(FWTS_ACPI_AC_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 AC device does not exist, skipping test"); > + return FWTS_SKIP; > + } > + > + return FWTS_OK; > +} > + > +static void method_test_PSR_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK) > + return; > + > + if (obj->Integer.Value > 2) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, > + "Method_PSRZeroOrOne", > + "%s returned 0x%8.8" PRIx64 ", expected 0 " > + "(offline) or 1 (online)", > + name, (uint64_t)obj->Integer.Value); > + } else > + fwts_method_passed_sane_uint64(fw, name, obj->Integer.Value); > +} > + > +static int method_test_PSR(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PSR", NULL, 0, method_test_PSR_return, NULL); > +} > + > +static void method_test_PCL_return(fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PCL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count); > +} > + > +static int method_test_PCL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_MANDATORY, > + &device, "_PCL", NULL, 0, method_test_PCL_return, NULL); > +} > + > +static void method_test_PIF_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + static const fwts_package_element elements[] = { > + { ACPI_TYPE_INTEGER, "Power Source State" }, > + { ACPI_TYPE_INTEGER, "Maximum Output Power" }, > + { ACPI_TYPE_INTEGER, "Maximum Input Power" }, > + { ACPI_TYPE_STRING, "Model Number" }, > + { ACPI_TYPE_STRING, "Serial Number" }, > + { ACPI_TYPE_STRING, "OEM Information" } > + }; > + > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_count_equal(fw, name, "_PIF", obj, 6) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_type(fw, name, "_PIF", obj, elements, 6) != FWTS_OK) > + return; > + > + fwts_acpi_object_dump(fw, obj); > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PIF(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PIF", NULL, 0, method_test_PIF_return, NULL); > +} > + > +static void method_test_PRL_return( > + fwts_framework *fw, > + char *name, > + ACPI_BUFFER *buf, > + ACPI_OBJECT *obj, > + void *private) > +{ > + FWTS_UNUSED(private); > + > + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) > + return; > + > + if (fwts_method_package_elements_all_type(fw, name, "_PRL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) > + return; > + > + fwts_method_passed_sane(fw, name, "package"); > +} > + > +static int method_test_PRL(fwts_framework *fw) > +{ > + return fwts_evaluate_method(fw, METHOD_OPTIONAL, > + &device, "_PRL", NULL, 0, method_test_PRL_return, NULL); > +} > + > +static fwts_framework_minor_test acpi_ac_tests[] = { > + { method_test_PSR, "Test _PSR (Power Source)." }, > + { method_test_PCL, "Test _PCL (Power Consumer List)." }, > + { method_test_PIF, "Test _PIF (Power Source Information)." }, > + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." }, > + { NULL, NULL } > +}; > + > +static int acpi_ac_deinit(fwts_framework *fw) > +{ > + FWTS_UNUSED(fw); > + fwts_acpica_deinit(); > + > + return FWTS_OK; > +} > + > +static fwts_framework_ops acpi_ac_ops = { > + .description = "AC adapter device test", > + .init = acpi_ac_init, > + .deinit = acpi_ac_deinit, > + .minor_tests = acpi_ac_tests > +}; > + > +FWTS_REGISTER("acpi_ac", &acpi_ac_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI) > + > +#endif > diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h > index 211be4a..41a5b6a 100644 > --- a/src/lib/include/fwts_acpi_object_eval.h > +++ b/src/lib/include/fwts_acpi_object_eval.h > @@ -72,4 +72,7 @@ void fwts_method_test_NULL_return(fwts_framework *fw, char *name, ACPI_BUFFER *b > void fwts_method_test_passed_failed_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > void fwts_method_test_polling_return( fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); > > +void fwts_evaluate_found_method(fwts_framework *fw, ACPI_HANDLE *parent, char *name, fwts_method_return check_func, void *private, ACPI_OBJECT_LIST *arg_list); > +int fwts_evaluate_method(fwts_framework *fw, uint32_t test_type, ACPI_HANDLE *parent, char *name, ACPI_OBJECT *args, uint32_t num_args, fwts_method_return check_func, void *private); > + > #endif > diff --git a/src/lib/src/fwts_acpi_object_eval.c b/src/lib/src/fwts_acpi_object_eval.c > index d8d3292..f2f32a4 100644 > --- a/src/lib/src/fwts_acpi_object_eval.c > +++ b/src/lib/src/fwts_acpi_object_eval.c > @@ -833,4 +833,80 @@ void fwts_method_test_polling_return( > } > } > > +void fwts_evaluate_found_method( > + fwts_framework *fw, > + ACPI_HANDLE *parent, > + char *name, > + fwts_method_return check_func, > + void *private, > + ACPI_OBJECT_LIST *arg_list) > +{ > + ACPI_BUFFER buf; > + ACPI_STATUS status; > + int sem_acquired; > + int sem_released; > + > + fwts_acpica_sem_count_clear(); > + > + buf.Length = ACPI_ALLOCATE_BUFFER; > + buf.Pointer = NULL; > + status = AcpiEvaluateObject(*parent, name, arg_list, &buf); > + > + if (ACPI_SUCCESS(status) && check_func != NULL) { > + ACPI_OBJECT *obj = buf.Pointer; > + check_func(fw, name, &buf, obj, private); > + } > + free(buf.Pointer); > + > + fwts_acpica_sem_count_get(&sem_acquired, &sem_released); > + if (sem_acquired != sem_released) { > + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired", > + "%s left %d locks in an acquired state.", > + name, sem_acquired - sem_released); > + fwts_advice(fw, > + "Locks left in an acquired state generally indicates " > + "that the AML code is not releasing a lock. This can " > + "sometimes occur when a method hits an error " > + "condition and exits prematurely without releasing an " > + "acquired lock. It may be occurring in the method " > + "being tested or other methods used while evaluating " > + "the method."); > + } > +} > + > +int fwts_evaluate_method(fwts_framework *fw, > + uint32_t test_type, /* Manditory or optional */ > + ACPI_HANDLE *parent, > + char *name, > + ACPI_OBJECT *args, > + uint32_t num_args, > + fwts_method_return check_func, > + void *private) > +{ > + ACPI_OBJECT_LIST arg_list; > + ACPI_HANDLE method; > + ACPI_STATUS status; > + > + status = AcpiGetHandle (*parent, name, &method); > + if (ACPI_SUCCESS(status)) { > + arg_list.Count = num_args; > + arg_list.Pointer = args; > + fwts_evaluate_found_method(fw, parent, name, check_func, private, &arg_list); > + } > + > + if (status == AE_NOT_FOUND && !(test_type & METHOD_SILENT)) { > + if (test_type & METHOD_MANDATORY) { > + fwts_failed(fw, LOG_LEVEL_CRITICAL, "MethodNotExist", "Object %s did not exist.", name); > + return FWTS_ERROR; > + } > + > + if (test_type & METHOD_OPTIONAL) { > + fwts_skipped(fw, "Skipping test for non-existent object %s.", name); > + return FWTS_SKIP; > + } > + } > + > + return FWTS_OK; > +} > + > #endif > Acked-by: Ivan Hu <ivan.hu@canonical.com>
diff --git a/src/Makefile.am b/src/Makefile.am index 6e28718..357d12b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -45,6 +45,7 @@ endif # fwts_SOURCES = main.c \ acpi/ac_adapter/ac_adapter.c \ + acpi/devices/ac_adapter/ac.c \ acpi/acpidump/acpidump.c \ acpi/acpiinfo/acpiinfo.c \ acpi/acpitables/acpitables.c \ diff --git a/src/acpi/devices/ac_adapter/ac.c b/src/acpi/devices/ac_adapter/ac.c new file mode 100644 index 0000000..d82b303 --- /dev/null +++ b/src/acpi/devices/ac_adapter/ac.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2017 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 <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <inttypes.h> +#include <string.h> + +#define FWTS_ACPI_AC_HID "ACPI0003" + +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_ac_init(fwts_framework *fw) +{ + ACPI_STATUS status; + + if (fwts_acpica_init(fw) != FWTS_OK) + return FWTS_ERROR; + + status = AcpiGetDevices(FWTS_ACPI_AC_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 AC device does not exist, skipping test"); + return FWTS_SKIP; + } + + return FWTS_OK; +} + +static void method_test_PSR_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_INTEGER) != FWTS_OK) + return; + + if (obj->Integer.Value > 2) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, + "Method_PSRZeroOrOne", + "%s returned 0x%8.8" PRIx64 ", expected 0 " + "(offline) or 1 (online)", + name, (uint64_t)obj->Integer.Value); + } else + fwts_method_passed_sane_uint64(fw, name, obj->Integer.Value); +} + +static int method_test_PSR(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, + &device, "_PSR", NULL, 0, method_test_PSR_return, NULL); +} + +static void method_test_PCL_return(fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) + return; + + if (fwts_method_package_elements_all_type(fw, name, "_PCL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) + return; + + fwts_passed(fw, "%s returned a sane package of %" PRIu32 " references.", name, obj->Package.Count); +} + +static int method_test_PCL(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_MANDATORY, + &device, "_PCL", NULL, 0, method_test_PCL_return, NULL); +} + +static void method_test_PIF_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + static const fwts_package_element elements[] = { + { ACPI_TYPE_INTEGER, "Power Source State" }, + { ACPI_TYPE_INTEGER, "Maximum Output Power" }, + { ACPI_TYPE_INTEGER, "Maximum Input Power" }, + { ACPI_TYPE_STRING, "Model Number" }, + { ACPI_TYPE_STRING, "Serial Number" }, + { ACPI_TYPE_STRING, "OEM Information" } + }; + + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) + return; + + if (fwts_method_package_count_equal(fw, name, "_PIF", obj, 6) != FWTS_OK) + return; + + if (fwts_method_package_elements_type(fw, name, "_PIF", obj, elements, 6) != FWTS_OK) + return; + + fwts_acpi_object_dump(fw, obj); + + fwts_method_passed_sane(fw, name, "package"); +} + +static int method_test_PIF(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_OPTIONAL, + &device, "_PIF", NULL, 0, method_test_PIF_return, NULL); +} + +static void method_test_PRL_return( + fwts_framework *fw, + char *name, + ACPI_BUFFER *buf, + ACPI_OBJECT *obj, + void *private) +{ + FWTS_UNUSED(private); + + if (fwts_method_check_type(fw, name, buf, ACPI_TYPE_PACKAGE) != FWTS_OK) + return; + + if (fwts_method_package_elements_all_type(fw, name, "_PRL", obj, ACPI_TYPE_LOCAL_REFERENCE) != FWTS_OK) + return; + + fwts_method_passed_sane(fw, name, "package"); +} + +static int method_test_PRL(fwts_framework *fw) +{ + return fwts_evaluate_method(fw, METHOD_OPTIONAL, + &device, "_PRL", NULL, 0, method_test_PRL_return, NULL); +} + +static fwts_framework_minor_test acpi_ac_tests[] = { + { method_test_PSR, "Test _PSR (Power Source)." }, + { method_test_PCL, "Test _PCL (Power Consumer List)." }, + { method_test_PIF, "Test _PIF (Power Source Information)." }, + { method_test_PRL, "Test _PRL (Power Source Redundancy List)." }, + { NULL, NULL } +}; + +static int acpi_ac_deinit(fwts_framework *fw) +{ + FWTS_UNUSED(fw); + fwts_acpica_deinit(); + + return FWTS_OK; +} + +static fwts_framework_ops acpi_ac_ops = { + .description = "AC adapter device test", + .init = acpi_ac_init, + .deinit = acpi_ac_deinit, + .minor_tests = acpi_ac_tests +}; + +FWTS_REGISTER("acpi_ac", &acpi_ac_ops, FWTS_TEST_ANYTIME, FWTS_FLAG_BATCH | FWTS_FLAG_TEST_ACPI) + +#endif diff --git a/src/lib/include/fwts_acpi_object_eval.h b/src/lib/include/fwts_acpi_object_eval.h index 211be4a..41a5b6a 100644 --- a/src/lib/include/fwts_acpi_object_eval.h +++ b/src/lib/include/fwts_acpi_object_eval.h @@ -72,4 +72,7 @@ void fwts_method_test_NULL_return(fwts_framework *fw, char *name, ACPI_BUFFER *b void fwts_method_test_passed_failed_return(fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); void fwts_method_test_polling_return( fwts_framework *fw, char *name, ACPI_BUFFER *buf, ACPI_OBJECT *obj, void *private); +void fwts_evaluate_found_method(fwts_framework *fw, ACPI_HANDLE *parent, char *name, fwts_method_return check_func, void *private, ACPI_OBJECT_LIST *arg_list); +int fwts_evaluate_method(fwts_framework *fw, uint32_t test_type, ACPI_HANDLE *parent, char *name, ACPI_OBJECT *args, uint32_t num_args, fwts_method_return check_func, void *private); + #endif diff --git a/src/lib/src/fwts_acpi_object_eval.c b/src/lib/src/fwts_acpi_object_eval.c index d8d3292..f2f32a4 100644 --- a/src/lib/src/fwts_acpi_object_eval.c +++ b/src/lib/src/fwts_acpi_object_eval.c @@ -833,4 +833,80 @@ void fwts_method_test_polling_return( } } +void fwts_evaluate_found_method( + fwts_framework *fw, + ACPI_HANDLE *parent, + char *name, + fwts_method_return check_func, + void *private, + ACPI_OBJECT_LIST *arg_list) +{ + ACPI_BUFFER buf; + ACPI_STATUS status; + int sem_acquired; + int sem_released; + + fwts_acpica_sem_count_clear(); + + buf.Length = ACPI_ALLOCATE_BUFFER; + buf.Pointer = NULL; + status = AcpiEvaluateObject(*parent, name, arg_list, &buf); + + if (ACPI_SUCCESS(status) && check_func != NULL) { + ACPI_OBJECT *obj = buf.Pointer; + check_func(fw, name, &buf, obj, private); + } + free(buf.Pointer); + + fwts_acpica_sem_count_get(&sem_acquired, &sem_released); + if (sem_acquired != sem_released) { + fwts_failed(fw, LOG_LEVEL_MEDIUM, "AMLLocksAcquired", + "%s left %d locks in an acquired state.", + name, sem_acquired - sem_released); + fwts_advice(fw, + "Locks left in an acquired state generally indicates " + "that the AML code is not releasing a lock. This can " + "sometimes occur when a method hits an error " + "condition and exits prematurely without releasing an " + "acquired lock. It may be occurring in the method " + "being tested or other methods used while evaluating " + "the method."); + } +} + +int fwts_evaluate_method(fwts_framework *fw, + uint32_t test_type, /* Manditory or optional */ + ACPI_HANDLE *parent, + char *name, + ACPI_OBJECT *args, + uint32_t num_args, + fwts_method_return check_func, + void *private) +{ + ACPI_OBJECT_LIST arg_list; + ACPI_HANDLE method; + ACPI_STATUS status; + + status = AcpiGetHandle (*parent, name, &method); + if (ACPI_SUCCESS(status)) { + arg_list.Count = num_args; + arg_list.Pointer = args; + fwts_evaluate_found_method(fw, parent, name, check_func, private, &arg_list); + } + + if (status == AE_NOT_FOUND && !(test_type & METHOD_SILENT)) { + if (test_type & METHOD_MANDATORY) { + fwts_failed(fw, LOG_LEVEL_CRITICAL, "MethodNotExist", "Object %s did not exist.", name); + return FWTS_ERROR; + } + + if (test_type & METHOD_OPTIONAL) { + fwts_skipped(fw, "Skipping test for non-existent object %s.", name); + return FWTS_SKIP; + } + } + + return FWTS_OK; +} + #endif
This type of tests provides flexibility to test control methods under ACPI devices, such as methods that are not required by OS but are mandatory by ACPI devices. Signed-off-by: Alex Hung <alex.hung@canonical.com> --- src/Makefile.am | 1 + src/acpi/devices/ac_adapter/ac.c | 204 ++++++++++++++++++++++++++++++++ src/lib/include/fwts_acpi_object_eval.h | 3 + src/lib/src/fwts_acpi_object_eval.c | 76 ++++++++++++ 4 files changed, 284 insertions(+) create mode 100644 src/acpi/devices/ac_adapter/ac.c