diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c index d2a8cfdaec2208f8ddecad23b92d1ec316202a3b..36518b4a79c26fe434685d9a06c8617c308e3f5f 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/dispatcher/dsutils.c @@ -472,7 +472,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, /* A valid name must be looked up in the namespace */ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && - (arg->common.value.string)) { + (arg->common.value.string) && + !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg)); @@ -595,7 +596,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, } else { /* Check for null name case */ - if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) { + if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) && + !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) { /* * If the name is null, this means that this is an * optional result parameter that was not specified @@ -617,7 +619,8 @@ acpi_ds_create_operand(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NOT_IMPLEMENTED); } - if (op_info->flags & AML_HAS_RETVAL) { + if ((op_info->flags & AML_HAS_RETVAL) + || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Argument previously created, already stacked\n")); @@ -759,3 +762,107 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state, ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index)); return_ACPI_STATUS(status); } + +/***************************************************************************** + * + * FUNCTION: acpi_ds_evaluate_name_path + * + * PARAMETERS: walk_state - Current state of the parse tree walk, + * the opcode of current operation should be + * AML_INT_NAMEPATH_OP + * + * RETURN: Status + * + * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent + * interpreter object, convert it to value, if needed, duplicate + * it, if needed, and push it onto the current result stack. + * + ****************************************************************************/ + +acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state) +{ + acpi_status status = AE_OK; + union acpi_parse_object *op = walk_state->op; + union acpi_operand_object **operand = &walk_state->operands[0]; + union acpi_operand_object *new_obj_desc; + u8 type; + + ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state); + + if (!op->common.parent) { + + /* This happens after certain exception processing */ + + goto exit; + } + + if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) || + (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) { + + /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */ + + goto exit; + } + + status = acpi_ds_create_operand(walk_state, op, 0); + if (ACPI_FAILURE(status)) { + goto exit; + } + + if (op->common.flags & ACPI_PARSEOP_TARGET) { + new_obj_desc = *operand; + goto push_result; + } + + type = ACPI_GET_OBJECT_TYPE(*operand); + + status = acpi_ex_resolve_to_value(operand, walk_state); + if (ACPI_FAILURE(status)) { + goto exit; + } + + if (type == ACPI_TYPE_INTEGER) { + + /* It was incremented by acpi_ex_resolve_to_value */ + + acpi_ut_remove_reference(*operand); + + status = + acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc, + walk_state); + if (ACPI_FAILURE(status)) { + goto exit; + } + } else { + /* + * The object either was anew created or is + * a Namespace node - don't decrement it. + */ + new_obj_desc = *operand; + } + + /* Cleanup for name-path operand */ + + status = acpi_ds_obj_stack_pop(1, walk_state); + if (ACPI_FAILURE(status)) { + walk_state->result_obj = new_obj_desc; + goto exit; + } + + push_result: + + walk_state->result_obj = new_obj_desc; + + status = acpi_ds_result_push(walk_state->result_obj, walk_state); + if (ACPI_SUCCESS(status)) { + + /* Force to take it from stack */ + + op->common.flags |= ACPI_PARSEOP_IN_STACK; + } + + exit: + + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c index 12b148587e3d467086f62c3a992f1f078fc2e5f3..514b9d2eb3a7f045aec3fe69cfd7d3ac1fd2d3e7 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/dispatcher/dswexec.c @@ -375,10 +375,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state) /* Decode the Opcode Class */ switch (op_class) { - case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */ + case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */ + + if (walk_state->opcode == AML_INT_NAMEPATH_OP) { + status = acpi_ds_evaluate_name_path(walk_state); + if (ACPI_FAILURE(status)) { + goto cleanup; + } + } break; - case AML_CLASS_EXECUTE: /* most operators with arguments */ + case AML_CLASS_EXECUTE: /* Most operators with arguments */ /* Build resolved operand stack */ diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c index c0837af0acb1a4bc3b3d3d95dd29724d3ea95432..c40b191f70b5d7c22c91532b9d645adb6b2b3426 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/executer/exutils.c @@ -217,9 +217,10 @@ void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc) /* * Object must be a valid number and we must be executing - * a control method + * a control method. NS node could be there for AML_INT_NAMEPATH_OP. */ if ((!obj_desc) || + (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) || (ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) { return; } diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c index 266dd0c1021864a77c61afc74d081f5919c59089..4348b05303989baa03b49ad4399de540a01402e5 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/parser/psloop.c @@ -182,6 +182,7 @@ acpi_ps_build_named_op(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state); unnamed_op->common.value.arg = NULL; + unnamed_op->common.arg_list_length = 0; unnamed_op->common.aml_opcode = walk_state->opcode; /* @@ -280,6 +281,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, acpi_status status = AE_OK; union acpi_parse_object *op; union acpi_parse_object *named_op = NULL; + union acpi_parse_object *parent_scope; + u8 argument_count; + const struct acpi_opcode_info *op_info; ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state); @@ -320,8 +324,23 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, op->named.length = 0; } - acpi_ps_append_arg(acpi_ps_get_parent_scope - (&(walk_state->parser_state)), op); + parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state)); + acpi_ps_append_arg(parent_scope, op); + + if (parent_scope) { + op_info = + acpi_ps_get_opcode_info(parent_scope->common.aml_opcode); + if (op_info->flags & AML_HAS_TARGET) { + argument_count = + acpi_ps_get_argument_count(op_info->type); + if (parent_scope->common.arg_list_length > + argument_count) { + op->common.flags |= ACPI_PARSEOP_TARGET; + } + } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { + op->common.flags |= ACPI_PARSEOP_TARGET; + } + } if (walk_state->descending_callback != NULL) { /* diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c index 9296e86761d74f2aa4000167f068f611d36486d3..3bf8105d6348f0ddafbcf7b6ec5aec22de660cbb 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/parser/psopcode.c @@ -49,6 +49,8 @@ #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psopcode") +const u8 acpi_gbl_argument_count[] = { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 }; + /******************************************************************************* * * NAME: acpi_gbl_aml_op_info @@ -59,6 +61,7 @@ ACPI_MODULE_NAME("psopcode") * the operand type. * ******************************************************************************/ + /* * Summary of opcode types/flags * @@ -176,6 +179,7 @@ ACPI_MODULE_NAME("psopcode") AML_CREATE_QWORD_FIELD_OP ******************************************************************************/ + /* * Master Opcode information table. A summary of everything we know about each * opcode, all in one place. @@ -779,3 +783,25 @@ char *acpi_ps_get_opcode_name(u16 opcode) #endif } + +/******************************************************************************* + * + * FUNCTION: acpi_ps_get_argument_count + * + * PARAMETERS: op_type - Type associated with the AML opcode + * + * RETURN: Argument count + * + * DESCRIPTION: Obtain the number of expected arguments for an AML opcode + * + ******************************************************************************/ + +u8 acpi_ps_get_argument_count(u32 op_type) +{ + + if (op_type <= AML_TYPE_EXEC_6A_0T_1R) { + return (acpi_gbl_argument_count[op_type]); + } + + return (0); +} diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c index 966e7ea2a0c49b2cdc9a25e76fb23f9c02a9a3d1..0e1a3226665d59da6bcf9309b9169e2b4cbfe645 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/parser/pstree.c @@ -171,6 +171,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) while (arg) { arg->common.parent = op; arg = arg->common.next; + + op->common.arg_list_length++; } } diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h index 70d649e92c41915bd812005d86428f36eecd4c50..3bffb4db4bceec8c8ca81b15a07dd718b680c0a3 100644 --- a/include/acpi/acdispat.h +++ b/include/acpi/acdispat.h @@ -269,6 +269,8 @@ acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state); void acpi_ds_clear_operands(struct acpi_walk_state *walk_state); +acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state); + /* * dswscope - Scope Stack manipulation */ diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h index 0b7c9a9e3c8488c539fc049fec25e0f3adf44278..946da60e36e7243c7c9b9d65a23bc9505684525d 100644 --- a/include/acpi/aclocal.h +++ b/include/acpi/aclocal.h @@ -603,6 +603,7 @@ union acpi_parse_value { union acpi_parse_object *next; /* Next op */\ struct acpi_namespace_node *node; /* For use by interpreter */\ union acpi_parse_value value; /* Value or args associated with the opcode */\ + u8 arg_list_length; /* Number of elements in the arg list */\ ACPI_DISASM_ONLY_MEMBERS (\ u8 disasm_flags; /* Used during AML disassembly */\ u8 disasm_opcode; /* Subtype used for disassembly */\ @@ -695,6 +696,8 @@ struct acpi_parse_state { #define ACPI_PARSEOP_NAMED 0x02 #define ACPI_PARSEOP_DEFERRED 0x04 #define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_STACK 0x10 +#define ACPI_PARSEOP_TARGET 0x20 #define ACPI_PARSEOP_IN_CACHE 0x80 /* Parse object disasm_flags */ diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h index 85c358e21014fd594b4c03e6e4c0e117f09c63b0..a3ae76b270afcd657d51754a88ad8e5178798496 100644 --- a/include/acpi/acparser.h +++ b/include/acpi/acparser.h @@ -109,6 +109,8 @@ const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode); char *acpi_ps_get_opcode_name(u16 opcode); +u8 acpi_ps_get_argument_count(u32 op_type); + /* * psparse - top level parsing routines */