summaryrefslogtreecommitdiff
path: root/drivers/acpi/acpica/psloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/psloop.c')
-rw-r--r--drivers/acpi/acpica/psloop.c77
1 files changed, 76 insertions, 1 deletions
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index 68422afc365f..ee840be150b5 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -497,6 +497,18 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
status =
acpi_ps_create_op(walk_state, aml_op_start, &op);
if (ACPI_FAILURE(status)) {
+ /*
+ * ACPI_PARSE_MODULE_LEVEL means that we are loading a table by
+ * executing it as a control method. However, if we encounter
+ * an error while loading the table, we need to keep trying to
+ * load the table rather than aborting the table load. Set the
+ * status to AE_OK to proceed with the table load.
+ */
+ if ((walk_state->
+ parse_flags & ACPI_PARSE_MODULE_LEVEL)
+ && status == AE_ALREADY_EXISTS) {
+ status = AE_OK;
+ }
if (status == AE_CTRL_PARSE_CONTINUE) {
continue;
}
@@ -515,6 +527,22 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+ if (walk_state->opcode == AML_SCOPE_OP) {
+ /*
+ * If the scope op fails to parse, skip the body of the
+ * scope op because the parse failure indicates that the
+ * device may not exist.
+ */
+ walk_state->parser_state.aml =
+ walk_state->aml + 1;
+ walk_state->parser_state.aml =
+ acpi_ps_get_next_package_end
+ (&walk_state->parser_state);
+ walk_state->aml =
+ walk_state->parser_state.aml;
+ ACPI_ERROR((AE_INFO,
+ "Skipping Scope block"));
+ }
continue;
}
@@ -557,7 +585,40 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
+ if ((walk_state->control_state) &&
+ ((walk_state->control_state->control.
+ opcode == AML_IF_OP)
+ || (walk_state->control_state->control.
+ opcode == AML_WHILE_OP))) {
+ /*
+ * If the if/while op fails to parse, we will skip parsing
+ * the body of the op.
+ */
+ parser_state->aml =
+ walk_state->control_state->control.
+ aml_predicate_start + 1;
+ parser_state->aml =
+ acpi_ps_get_next_package_end
+ (parser_state);
+ walk_state->aml = parser_state->aml;
+
+ ACPI_ERROR((AE_INFO,
+ "Skipping While/If block"));
+ if (*walk_state->aml == AML_ELSE_OP) {
+ ACPI_ERROR((AE_INFO,
+ "Skipping Else block"));
+ walk_state->parser_state.aml =
+ walk_state->aml + 1;
+ walk_state->parser_state.aml =
+ acpi_ps_get_next_package_end
+ (parser_state);
+ walk_state->aml =
+ parser_state->aml;
+ }
+ ACPI_FREE(acpi_ut_pop_generic_state
+ (&walk_state->control_state));
+ }
+ op = NULL;
continue;
}
}
@@ -645,6 +706,20 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
acpi_ps_next_parse_state(walk_state, op, status);
if (status == AE_CTRL_PENDING) {
status = AE_OK;
+ } else
+ if ((walk_state->
+ parse_flags & ACPI_PARSE_MODULE_LEVEL)
+ && ACPI_FAILURE(status)) {
+ /*
+ * ACPI_PARSE_MODULE_LEVEL means that we are loading a table by
+ * executing it as a control method. However, if we encounter
+ * an error while loading the table, we need to keep trying to
+ * load the table rather than aborting the table load. Set the
+ * status to AE_OK to proceed with the table load. If we get a
+ * failure at this point, it means that the dispatcher got an
+ * error while processing Op (most likely an AML operand error.
+ */
+ status = AE_OK;
}
}