ACPICA: Implemented full support for deferred execution for the TermArg string arguments for DataTableRegion

This enables forward references and full operand resolution for
the three string arguments. Similar to OperationRegion deferred
argument execution.)

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

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>
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index f0847ee..a3f2979 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -49,6 +49,7 @@
 #include <acpi/acinterp.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acevents.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsopcode")
@@ -782,6 +783,108 @@
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_ds_eval_table_region_operands
+ *
+ * PARAMETERS:  walk_state      - Current walk
+ *              Op              - A valid region Op object
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get region address and length
+ *              Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_table_region_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;
+	struct acpi_namespace_node *node;
+	union acpi_parse_object *next_op;
+	acpi_native_uint table_index;
+	struct acpi_table_header *table;
+
+	ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
+
+	/*
+	 * This is where we evaluate the signature_string and oem_iDString
+	 * and oem_table_iDString of the data_table_region declaration
+	 */
+	node = op->common.node;
+
+	/* next_op points to signature_string op */
+
+	next_op = op->common.value.arg;
+
+	/*
+	 * Evaluate/create the signature_string and oem_iDString
+	 * and oem_table_iDString operands
+	 */
+	status = acpi_ds_create_operands(walk_state, next_op);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	/*
+	 * Resolve the signature_string and oem_iDString
+	 * and oem_table_iDString operands
+	 */
+	status = acpi_ex_resolve_operands(op->common.aml_opcode,
+					  ACPI_WALK_OPERANDS, 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");
+
+	operand = &walk_state->operands[0];
+
+	/* Find the ACPI table */
+
+	status = acpi_tb_find_table(operand[0]->string.pointer,
+				    operand[1]->string.pointer,
+				    operand[2]->string.pointer, &table_index);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	acpi_ut_remove_reference(operand[0]);
+	acpi_ut_remove_reference(operand[1]);
+	acpi_ut_remove_reference(operand[2]);
+
+	status = acpi_get_table_by_index(table_index, &table);
+	if (ACPI_FAILURE(status)) {
+		return_ACPI_STATUS(status);
+	}
+
+	obj_desc = acpi_ns_get_attached_object(node);
+	if (!obj_desc) {
+		return_ACPI_STATUS(AE_NOT_EXIST);
+	}
+
+	obj_desc->region.address =
+	    (acpi_physical_address) ACPI_TO_INTEGER(table);
+	obj_desc->region.length = table->length;
+
+	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+			  obj_desc,
+			  ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+			  obj_desc->region.length));
+
+	/* Now the address and length are valid for this opregion */
+
+	obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+	return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_ds_eval_data_object_operands
  *
  * PARAMETERS:  walk_state      - Current walk
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 6af4671..8ba4bb3 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -641,6 +641,17 @@
 				if (ACPI_FAILURE(status)) {
 					break;
 				}
+			} else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+				ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+						  "Executing DataTableRegion Strings Op=%p\n",
+						  op));
+
+				status =
+				    acpi_ds_eval_table_region_operands
+				    (walk_state, op);
+				if (ACPI_FAILURE(status)) {
+					break;
+				}
 			}
 			break;
 
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 8ab9d1b..ec68c1d 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -443,6 +443,15 @@
 			if (ACPI_FAILURE(status)) {
 				return_ACPI_STATUS(status);
 			}
+		} else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+			status =
+			    acpi_ex_create_region(op->named.data,
+						  op->named.length,
+						  REGION_DATA_TABLE,
+						  walk_state);
+			if (ACPI_FAILURE(status)) {
+				return_ACPI_STATUS(status);
+			}
 		}
 	}
 #endif
@@ -823,6 +832,7 @@
 	struct acpi_namespace_node *new_node;
 #ifndef ACPI_NO_METHOD_EXECUTION
 	u32 i;
+	u8 region_space;
 #endif
 
 	ACPI_FUNCTION_TRACE(ds_load2_end_op);
@@ -1003,11 +1013,6 @@
 			status = acpi_ex_create_event(walk_state);
 			break;
 
-		case AML_DATA_REGION_OP:
-
-			status = acpi_ex_create_table_region(walk_state);
-			break;
-
 		case AML_ALIAS_OP:
 
 			status = acpi_ex_create_alias(walk_state);
@@ -1035,6 +1040,15 @@
 		switch (op->common.aml_opcode) {
 #ifndef ACPI_NO_METHOD_EXECUTION
 		case AML_REGION_OP:
+		case AML_DATA_REGION_OP:
+
+			if (op->common.aml_opcode == AML_REGION_OP) {
+				region_space = (acpi_adr_space_type)
+				    ((op->common.value.arg)->common.value.
+				     integer);
+			} else {
+				region_space = REGION_DATA_TABLE;
+			}
 
 			/*
 			 * If we are executing a method, initialize the region
@@ -1043,10 +1057,7 @@
 				status =
 				    acpi_ex_create_region(op->named.data,
 							  op->named.length,
-							  (acpi_adr_space_type)
-							  ((op->common.value.
-							    arg)->common.value.
-							   integer),
+							  region_space,
 							  walk_state);
 				if (ACPI_FAILURE(status)) {
 					return (status);