Skip to content

Commit

Permalink
ACPICA: Implemented full argument resolution support for the BankValu…
Browse files Browse the repository at this point in the history
…e argument to BankField

Previously, only constants were supported, now any TermArg may
be used.

http://www.acpica.org/bugzilla/show_bug.cgi?id=387
http://www.acpica.org/bugzilla/show_bug.cgi?id=393

Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Alexey Starikovskiy <astarikovskiy@suse.de>
Signed-off-by: Len Brown <len.brown@intel.com>
  • Loading branch information
Lin Ming authored and Len Brown committed Apr 22, 2008
1 parent 57345ee commit ef805d9
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 42 deletions.
80 changes: 41 additions & 39 deletions drivers/acpi/dispatcher/dsfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,17 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info,
arg->common.node = info->field_node;
info->field_bit_length = arg->common.value.size;

/* Create and initialize an object for the new Field Node */

status = acpi_ex_prep_field_value(info);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
/*
* If there is no object attached to the node, this node was just created
* and we need to create the field object. Otherwise, this was a lookup
* of an existing node and we don't want to create the field object again.
*/
if (!acpi_ns_get_attached_object
(info->field_node)) {
status = acpi_ex_prep_field_value(info);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
}
}

Expand Down Expand Up @@ -399,9 +405,22 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
union acpi_parse_object *arg = NULL;
struct acpi_namespace_node *node;
u8 type = 0;
u32 flags;

ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);

/*
* During the load phase, we want to enter the name of the field into
* the namespace. During the execute phase (when we evaluate the bank_value
* operand), we want to lookup the name.
*/
if (walk_state->deferred_node) {
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
} else {
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;
}

switch (walk_state->opcode) {
case AML_FIELD_OP:
arg = acpi_ps_get_arg(op, 2);
Expand Down Expand Up @@ -433,10 +452,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
status = acpi_ns_lookup(walk_state->scope_info,
(char *)&arg->named.name,
type, ACPI_IMODE_LOAD_PASS1,
ACPI_NS_NO_UPSEARCH |
ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND,
walk_state, &node);
flags, walk_state, &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
status);
Expand Down Expand Up @@ -466,7 +482,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op,
*
* PARAMETERS: Op - Op containing the Field definition and args
* region_node - Object for the containing Operation Region
* ` walk_state - Current method state
* walk_state - Current method state
*
* RETURN: Status
*
Expand Down Expand Up @@ -513,36 +529,13 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
return_ACPI_STATUS(status);
}

/* Third arg is the bank_value */

/* TBD: This arg is a term_arg, not a constant, and must be evaluated */

/*
* Third arg is the bank_value
* This arg is a term_arg, not a constant
* It will be evaluated later, by acpi_ds_eval_bank_field_operands
*/
arg = arg->common.next;

/* Currently, only the following constants are supported */

switch (arg->common.aml_opcode) {
case AML_ZERO_OP:
info.bank_value = 0;
break;

case AML_ONE_OP:
info.bank_value = 1;
break;

case AML_BYTE_OP:
case AML_WORD_OP:
case AML_DWORD_OP:
case AML_QWORD_OP:
info.bank_value = (u32) arg->common.value.integer;
break;

default:
info.bank_value = 0;
ACPI_ERROR((AE_INFO,
"Non-constant BankValue for BankField is not implemented"));
}

/* Fourth arg is the field flags */

arg = arg->common.next;
Expand All @@ -553,8 +546,17 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
info.region_node = region_node;

status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
/*
* Use Info.data_register_node to store bank_field Op
* It's safe because data_register_node will never be used when create bank field
* We store aml_start and aml_length in the bank_field Op for late evaluation
* Used in acpi_ex_prep_field_value(Info)
*
* TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
*/
info.data_register_node = (struct acpi_namespace_node *)op;

status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
return_ACPI_STATUS(status);
}

Expand Down
144 changes: 144 additions & 0 deletions drivers/acpi/dispatcher/dsopcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,50 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ds_get_bank_field_arguments
*
* PARAMETERS: obj_desc - A valid bank_field object
*
* RETURN: Status.
*
* DESCRIPTION: Get bank_field bank_value. This implements the late
* evaluation of these field attributes.
*
******************************************************************************/

acpi_status
acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
{
union acpi_operand_object *extra_desc;
struct acpi_namespace_node *node;
acpi_status status;

ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);

if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
return_ACPI_STATUS(AE_OK);
}

/* Get the AML pointer (method object) and bank_field node */

extra_desc = acpi_ns_get_secondary_object(obj_desc);
node = obj_desc->bank_field.node;

ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
(ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
acpi_ut_get_node_name(node)));

/* Execute the AML code for the term_arg arguments */

status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ds_get_buffer_arguments
Expand Down Expand Up @@ -985,6 +1029,106 @@ acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ds_eval_bank_field_operands
*
* PARAMETERS: walk_state - Current walk
* Op - A valid bank_field Op object
*
* RETURN: Status
*
* DESCRIPTION: Get bank_field bank_value
* Called from acpi_ds_exec_end_op during bank_field parse tree walk
*
******************************************************************************/

acpi_status
acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *op)
{
acpi_status status;
union acpi_operand_object *obj_desc;
union acpi_operand_object *operand_desc;
struct acpi_namespace_node *node;
union acpi_parse_object *next_op;
union acpi_parse_object *arg;

ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op);

/*
* This is where we evaluate the bank_value field of the
* bank_field declaration
*/

/* next_op points to the op that holds the Region */

next_op = op->common.value.arg;

/* next_op points to the op that holds the Bank Register */

next_op = next_op->common.next;

/* next_op points to the op that holds the Bank Value */

next_op = next_op->common.next;

/*
* Set proper index into operand stack for acpi_ds_obj_stack_push
* invoked inside acpi_ds_create_operand.
*
* We use walk_state->Operands[0] to store the evaluated bank_value
*/
walk_state->operand_index = 0;

status = acpi_ds_create_operand(walk_state, next_op, 0);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}

status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}

ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
acpi_ps_get_opcode_name(op->common.aml_opcode),
1, "after AcpiExResolveOperands");

/*
* Get the bank_value operand and save it
* (at Top of stack)
*/
operand_desc = walk_state->operands[0];

/* Arg points to the start Bank Field */

arg = acpi_ps_get_arg(op, 4);
while (arg) {

/* Ignore OFFSET and ACCESSAS terms here */

if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
node = arg->common.node;

obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
return_ACPI_STATUS(AE_NOT_EXIST);
}

obj_desc->bank_field.value =
(u32) operand_desc->integer.value;
}

/* Move to next field in the list */

arg = arg->common.next;
}

acpi_ut_remove_reference(operand_desc);
return_ACPI_STATUS(status);
}

/*******************************************************************************
*
* FUNCTION: acpi_ds_exec_begin_control_op
Expand Down
4 changes: 3 additions & 1 deletion drivers/acpi/dispatcher/dsutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,9 @@ acpi_ds_is_result_used(union acpi_parse_object * op,
AML_VAR_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
|| (op->common.parent->common.aml_opcode ==
AML_INT_EVAL_SUBTREE_OP)) {
AML_INT_EVAL_SUBTREE_OP)
|| (op->common.parent->common.aml_opcode ==
AML_BANK_FIELD_OP)) {
/*
* These opcodes allow term_arg(s) as operands and therefore
* the operands can be method calls. The result is used.
Expand Down
11 changes: 11 additions & 0 deletions drivers/acpi/dispatcher/dswexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,17 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
if (ACPI_FAILURE(status)) {
break;
}
} else if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Executing BankField Op=%p\n",
op));

status =
acpi_ds_eval_bank_field_operands(walk_state,
op);
if (ACPI_FAILURE(status)) {
break;
}
}
break;

Expand Down
15 changes: 15 additions & 0 deletions drivers/acpi/executer/exprep.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
union acpi_operand_object *obj_desc;
union acpi_operand_object *second_desc = NULL;
u32 type;
acpi_status status;

Expand Down Expand Up @@ -494,6 +495,20 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
obj_desc->field.access_byte_width,
obj_desc->bank_field.region_obj,
obj_desc->bank_field.bank_obj));

/*
* Remember location in AML stream of the field unit
* opcode and operands -- since the bank_value
* operands must be evaluated.
*/
second_desc = obj_desc->common.next_object;
second_desc->extra.aml_start =
((union acpi_parse_object *)(info->data_register_node))->
named.data;
second_desc->extra.aml_length =
((union acpi_parse_object *)(info->data_register_node))->
named.length;

break;

case ACPI_TYPE_LOCAL_INDEX_FIELD:
Expand Down
10 changes: 10 additions & 0 deletions drivers/acpi/namespace/nsinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
info->field_count++;
break;

case ACPI_TYPE_LOCAL_BANK_FIELD:
info->field_count++;
break;

case ACPI_TYPE_BUFFER:
info->buffer_count++;
break;
Expand Down Expand Up @@ -287,6 +291,12 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
status = acpi_ds_get_buffer_field_arguments(obj_desc);
break;

case ACPI_TYPE_LOCAL_BANK_FIELD:

info->field_init++;
status = acpi_ds_get_bank_field_arguments(obj_desc);
break;

case ACPI_TYPE_BUFFER:

info->buffer_init++;
Expand Down
Loading

0 comments on commit ef805d9

Please sign in to comment.