diff options
-rw-r--r-- | drivers/acpi/acpica/acnamesp.h | 4 | ||||
-rw-r--r-- | drivers/acpi/acpica/nspredef.c | 30 | ||||
-rw-r--r-- | drivers/acpi/acpica/nsrepair.c | 52 |
3 files changed, 84 insertions, 2 deletions
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 908cfdd3b895..f75a7a01b875 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -278,6 +278,10 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, u32 package_index, union acpi_operand_object **return_object_ptr); +acpi_status +acpi_ns_repair_package_list(struct acpi_predefined_data *data, + union acpi_operand_object **obj_desc_ptr); + /* * nssearch - Namespace searching and entry */ diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index e3f08dcb5275..0091504df074 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -566,9 +566,35 @@ acpi_ns_check_package(struct acpi_predefined_data *data, case ACPI_PTYPE2_COUNT: /* - * These types all return a single package that consists of a - * variable number of sub-packages. + * These types all return a single Package that consists of a + * variable number of sub-Packages. + * + * First, ensure that the first element is a sub-Package. If not, + * the BIOS may have incorrectly returned the object as a single + * package instead of a Package of Packages (a common error if + * there is only one entry). We may be able to repair this by + * wrapping the returned Package with a new outer Package. */ + if ((*elements)->common.type != ACPI_TYPE_PACKAGE) { + + /* Create the new outer package and populate it */ + + status = + acpi_ns_repair_package_list(data, + return_object_ptr); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Update locals to point to the new package (of 1 element) */ + + return_object = *return_object_ptr; + elements = return_object->package.elements; + count = 1; + } + + /* Validate each sub-Package in the parent Package */ + for (i = 0; i < count; i++) { sub_package = *elements; sub_elements = sub_package->package.elements; diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index b64751eacc53..db2b2a99c3a8 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -149,3 +149,55 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, return (AE_AML_OPERAND_TYPE); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_package_list + * + * PARAMETERS: Data - Pointer to validation data structure + * obj_desc_ptr - Pointer to the object to repair. The new + * package object is returned here, + * overwriting the old object. + * + * RETURN: Status, new object in *obj_desc_ptr + * + * DESCRIPTION: Repair a common problem with objects that are defined to return + * a variable-length Package of Packages. If the variable-length + * is one, some BIOS code mistakenly simply declares a single + * Package instead of a Package with one sub-Package. This + * function attempts to repair this error by wrapping a Package + * object around the original Package, creating the correct + * Package with one sub-Package. + * + * Names that can be repaired in this manner include: + * _ALR, _CSD, _HPX, _MLS, _PRT, _PSS, _TRT, TSS + * + ******************************************************************************/ + +acpi_status +acpi_ns_repair_package_list(struct acpi_predefined_data *data, + union acpi_operand_object **obj_desc_ptr) +{ + union acpi_operand_object *pkg_obj_desc; + + /* + * Create the new outer package and populate it. The new package will + * have a single element, the lone subpackage. + */ + pkg_obj_desc = acpi_ut_create_package_object(1); + if (!pkg_obj_desc) { + return (AE_NO_MEMORY); + } + + pkg_obj_desc->package.elements[0] = *obj_desc_ptr; + + /* Return the new object in the object pointer */ + + *obj_desc_ptr = pkg_obj_desc; + data->flags |= ACPI_OBJECT_REPAIRED; + + ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, data->node_flags, + "Incorrectly formed Package, attempting repair")); + + return (AE_OK); +} |