xref: /openbmc/linux/drivers/acpi/acpica/excreate.c (revision 612c2932)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: excreate - Named object creation
595b482a8SLen Brown  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acinterp.h"
13e2f7a777SLen Brown #include "amlcode.h"
14e2f7a777SLen Brown #include "acnamesp.h"
1595b482a8SLen Brown 
1695b482a8SLen Brown #define _COMPONENT          ACPI_EXECUTER
1795b482a8SLen Brown ACPI_MODULE_NAME("excreate")
1895b482a8SLen Brown /*******************************************************************************
1995b482a8SLen Brown  *
2095b482a8SLen Brown  * FUNCTION:    acpi_ex_create_alias
2195b482a8SLen Brown  *
2295b482a8SLen Brown  * PARAMETERS:  walk_state           - Current state, contains operands
2395b482a8SLen Brown  *
2495b482a8SLen Brown  * RETURN:      Status
2595b482a8SLen Brown  *
2695b482a8SLen Brown  * DESCRIPTION: Create a new named alias
2795b482a8SLen Brown  *
2895b482a8SLen Brown  ******************************************************************************/
acpi_ex_create_alias(struct acpi_walk_state * walk_state)2995b482a8SLen Brown acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state)
3095b482a8SLen Brown {
3195b482a8SLen Brown 	struct acpi_namespace_node *target_node;
3295b482a8SLen Brown 	struct acpi_namespace_node *alias_node;
3395b482a8SLen Brown 	acpi_status status = AE_OK;
3495b482a8SLen Brown 
3595b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_create_alias);
3695b482a8SLen Brown 
3795b482a8SLen Brown 	/* Get the source/alias operands (both namespace nodes) */
3895b482a8SLen Brown 
3995b482a8SLen Brown 	alias_node = (struct acpi_namespace_node *)walk_state->operands[0];
4095b482a8SLen Brown 	target_node = (struct acpi_namespace_node *)walk_state->operands[1];
4195b482a8SLen Brown 
4295b482a8SLen Brown 	if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) ||
4395b482a8SLen Brown 	    (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
4495b482a8SLen Brown 		/*
4595b482a8SLen Brown 		 * Dereference an existing alias so that we don't create a chain
4695b482a8SLen Brown 		 * of aliases. With this code, we guarantee that an alias is
4795b482a8SLen Brown 		 * always exactly one level of indirection away from the
4895b482a8SLen Brown 		 * actual aliased name.
4995b482a8SLen Brown 		 */
5095b482a8SLen Brown 		target_node =
5195b482a8SLen Brown 		    ACPI_CAST_PTR(struct acpi_namespace_node,
5295b482a8SLen Brown 				  target_node->object);
5395b482a8SLen Brown 	}
5495b482a8SLen Brown 
554e6cbe56SAlex James 	/* Ensure that the target node is valid */
56a5b6e982SBob Moore 
574e6cbe56SAlex James 	if (!target_node) {
584e6cbe56SAlex James 		return_ACPI_STATUS(AE_NULL_OBJECT);
594e6cbe56SAlex James 	}
604e6cbe56SAlex James 
61a5b6e982SBob Moore 	/* Construct the alias object (a namespace node) */
62a5b6e982SBob Moore 
6395b482a8SLen Brown 	switch (target_node->type) {
64a5b6e982SBob Moore 	case ACPI_TYPE_METHOD:
6595b482a8SLen Brown 		/*
66a5b6e982SBob Moore 		 * Control method aliases need to be differentiated with
67a5b6e982SBob Moore 		 * a special type
6895b482a8SLen Brown 		 */
69a5b6e982SBob Moore 		alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
70a5b6e982SBob Moore 		break;
71a5b6e982SBob Moore 
72a5b6e982SBob Moore 	default:
7395b482a8SLen Brown 		/*
74a5b6e982SBob Moore 		 * All other object types.
75a5b6e982SBob Moore 		 *
7695b482a8SLen Brown 		 * The new alias has the type ALIAS and points to the original
7795b482a8SLen Brown 		 * NS node, not the object itself.
7895b482a8SLen Brown 		 */
7995b482a8SLen Brown 		alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
8095b482a8SLen Brown 		alias_node->object =
8195b482a8SLen Brown 		    ACPI_CAST_PTR(union acpi_operand_object, target_node);
8295b482a8SLen Brown 		break;
8395b482a8SLen Brown 	}
8495b482a8SLen Brown 
8595b482a8SLen Brown 	/* Since both operands are Nodes, we don't need to delete them */
8695b482a8SLen Brown 
87a5b6e982SBob Moore 	alias_node->object =
88a5b6e982SBob Moore 	    ACPI_CAST_PTR(union acpi_operand_object, target_node);
8995b482a8SLen Brown 	return_ACPI_STATUS(status);
9095b482a8SLen Brown }
9195b482a8SLen Brown 
9295b482a8SLen Brown /*******************************************************************************
9395b482a8SLen Brown  *
9495b482a8SLen Brown  * FUNCTION:    acpi_ex_create_event
9595b482a8SLen Brown  *
9695b482a8SLen Brown  * PARAMETERS:  walk_state          - Current state
9795b482a8SLen Brown  *
9895b482a8SLen Brown  * RETURN:      Status
9995b482a8SLen Brown  *
10095b482a8SLen Brown  * DESCRIPTION: Create a new event object
10195b482a8SLen Brown  *
10295b482a8SLen Brown  ******************************************************************************/
10395b482a8SLen Brown 
acpi_ex_create_event(struct acpi_walk_state * walk_state)10495b482a8SLen Brown acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state)
10595b482a8SLen Brown {
10695b482a8SLen Brown 	acpi_status status;
10795b482a8SLen Brown 	union acpi_operand_object *obj_desc;
10895b482a8SLen Brown 
10995b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_create_event);
11095b482a8SLen Brown 
11195b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_EVENT);
11295b482a8SLen Brown 	if (!obj_desc) {
11395b482a8SLen Brown 		status = AE_NO_MEMORY;
11495b482a8SLen Brown 		goto cleanup;
11595b482a8SLen Brown 	}
11695b482a8SLen Brown 
11795b482a8SLen Brown 	/*
11895b482a8SLen Brown 	 * Create the actual OS semaphore, with zero initial units -- meaning
11995b482a8SLen Brown 	 * that the event is created in an unsignalled state
12095b482a8SLen Brown 	 */
12195b482a8SLen Brown 	status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0,
12295b482a8SLen Brown 					  &obj_desc->event.os_semaphore);
12395b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
12495b482a8SLen Brown 		goto cleanup;
12595b482a8SLen Brown 	}
12695b482a8SLen Brown 
12795b482a8SLen Brown 	/* Attach object to the Node */
12895b482a8SLen Brown 
1291fad8738SBob Moore 	status = acpi_ns_attach_object((struct acpi_namespace_node *)
1301fad8738SBob Moore 				       walk_state->operands[0], obj_desc,
1311fad8738SBob Moore 				       ACPI_TYPE_EVENT);
13295b482a8SLen Brown 
13395b482a8SLen Brown cleanup:
13495b482a8SLen Brown 	/*
13595b482a8SLen Brown 	 * Remove local reference to the object (on error, will cause deletion
13695b482a8SLen Brown 	 * of both object and semaphore if present.)
13795b482a8SLen Brown 	 */
13895b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
13995b482a8SLen Brown 	return_ACPI_STATUS(status);
14095b482a8SLen Brown }
14195b482a8SLen Brown 
14295b482a8SLen Brown /*******************************************************************************
14395b482a8SLen Brown  *
14495b482a8SLen Brown  * FUNCTION:    acpi_ex_create_mutex
14595b482a8SLen Brown  *
14695b482a8SLen Brown  * PARAMETERS:  walk_state          - Current state
14795b482a8SLen Brown  *
14895b482a8SLen Brown  * RETURN:      Status
14995b482a8SLen Brown  *
15095b482a8SLen Brown  * DESCRIPTION: Create a new mutex object
15195b482a8SLen Brown  *
15295b482a8SLen Brown  *              Mutex (Name[0], sync_level[1])
15395b482a8SLen Brown  *
15495b482a8SLen Brown  ******************************************************************************/
15595b482a8SLen Brown 
acpi_ex_create_mutex(struct acpi_walk_state * walk_state)15695b482a8SLen Brown acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
15795b482a8SLen Brown {
15895b482a8SLen Brown 	acpi_status status = AE_OK;
15995b482a8SLen Brown 	union acpi_operand_object *obj_desc;
16095b482a8SLen Brown 
16195b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ex_create_mutex, ACPI_WALK_OPERANDS);
16295b482a8SLen Brown 
16395b482a8SLen Brown 	/* Create the new mutex object */
16495b482a8SLen Brown 
16595b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
16695b482a8SLen Brown 	if (!obj_desc) {
16795b482a8SLen Brown 		status = AE_NO_MEMORY;
16895b482a8SLen Brown 		goto cleanup;
16995b482a8SLen Brown 	}
17095b482a8SLen Brown 
17195b482a8SLen Brown 	/* Create the actual OS Mutex */
17295b482a8SLen Brown 
17395b482a8SLen Brown 	status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex);
17495b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
17595b482a8SLen Brown 		goto cleanup;
17695b482a8SLen Brown 	}
17795b482a8SLen Brown 
17895b482a8SLen Brown 	/* Init object and attach to NS node */
17995b482a8SLen Brown 
1801f86e8c1SLv Zheng 	obj_desc->mutex.sync_level = (u8)walk_state->operands[1]->integer.value;
18195b482a8SLen Brown 	obj_desc->mutex.node =
18295b482a8SLen Brown 	    (struct acpi_namespace_node *)walk_state->operands[0];
18395b482a8SLen Brown 
18495b482a8SLen Brown 	status =
18595b482a8SLen Brown 	    acpi_ns_attach_object(obj_desc->mutex.node, obj_desc,
18695b482a8SLen Brown 				  ACPI_TYPE_MUTEX);
18795b482a8SLen Brown 
18895b482a8SLen Brown cleanup:
18995b482a8SLen Brown 	/*
19095b482a8SLen Brown 	 * Remove local reference to the object (on error, will cause deletion
19195b482a8SLen Brown 	 * of both object and semaphore if present.)
19295b482a8SLen Brown 	 */
19395b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
19495b482a8SLen Brown 	return_ACPI_STATUS(status);
19595b482a8SLen Brown }
19695b482a8SLen Brown 
19795b482a8SLen Brown /*******************************************************************************
19895b482a8SLen Brown  *
19995b482a8SLen Brown  * FUNCTION:    acpi_ex_create_region
20095b482a8SLen Brown  *
20195b482a8SLen Brown  * PARAMETERS:  aml_start           - Pointer to the region declaration AML
20295b482a8SLen Brown  *              aml_length          - Max length of the declaration AML
203ec463666SBob Moore  *              space_id            - Address space ID for the region
20495b482a8SLen Brown  *              walk_state          - Current state
20595b482a8SLen Brown  *
20695b482a8SLen Brown  * RETURN:      Status
20795b482a8SLen Brown  *
20895b482a8SLen Brown  * DESCRIPTION: Create a new operation region object
20995b482a8SLen Brown  *
21095b482a8SLen Brown  ******************************************************************************/
21195b482a8SLen Brown 
21295b482a8SLen Brown acpi_status
acpi_ex_create_region(u8 * aml_start,u32 aml_length,u8 space_id,struct acpi_walk_state * walk_state)21395b482a8SLen Brown acpi_ex_create_region(u8 * aml_start,
21495b482a8SLen Brown 		      u32 aml_length,
215ec463666SBob Moore 		      u8 space_id, struct acpi_walk_state *walk_state)
21695b482a8SLen Brown {
21795b482a8SLen Brown 	acpi_status status;
21895b482a8SLen Brown 	union acpi_operand_object *obj_desc;
21995b482a8SLen Brown 	struct acpi_namespace_node *node;
22095b482a8SLen Brown 	union acpi_operand_object *region_obj2;
22195b482a8SLen Brown 
22295b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ex_create_region);
22395b482a8SLen Brown 
22495b482a8SLen Brown 	/* Get the Namespace Node */
22595b482a8SLen Brown 
22695b482a8SLen Brown 	node = walk_state->op->common.node;
22795b482a8SLen Brown 
22895b482a8SLen Brown 	/*
22995b482a8SLen Brown 	 * If the region object is already attached to this node,
23095b482a8SLen Brown 	 * just return
23195b482a8SLen Brown 	 */
23295b482a8SLen Brown 	if (acpi_ns_get_attached_object(node)) {
23395b482a8SLen Brown 		return_ACPI_STATUS(AE_OK);
23495b482a8SLen Brown 	}
23595b482a8SLen Brown 
23695b482a8SLen Brown 	/*
23795b482a8SLen Brown 	 * Space ID must be one of the predefined IDs, or in the user-defined
23895b482a8SLen Brown 	 * range
23995b482a8SLen Brown 	 */
240ec463666SBob Moore 	if (!acpi_is_valid_space_id(space_id)) {
241ec463666SBob Moore 		/*
242ec463666SBob Moore 		 * Print an error message, but continue. We don't want to abort
243ec463666SBob Moore 		 * a table load for this exception. Instead, if the region is
244ec463666SBob Moore 		 * actually used at runtime, abort the executing method.
245ec463666SBob Moore 		 */
246ec463666SBob Moore 		ACPI_ERROR((AE_INFO,
247ec463666SBob Moore 			    "Invalid/unknown Address Space ID: 0x%2.2X",
248ec463666SBob Moore 			    space_id));
24995b482a8SLen Brown 	}
25095b482a8SLen Brown 
251f6a22b0bSBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n",
252ec463666SBob Moore 			  acpi_ut_get_region_name(space_id), space_id));
25395b482a8SLen Brown 
25495b482a8SLen Brown 	/* Create the region descriptor */
25595b482a8SLen Brown 
25695b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
25795b482a8SLen Brown 	if (!obj_desc) {
25895b482a8SLen Brown 		status = AE_NO_MEMORY;
25995b482a8SLen Brown 		goto cleanup;
26095b482a8SLen Brown 	}
26195b482a8SLen Brown 
26295b482a8SLen Brown 	/*
26395b482a8SLen Brown 	 * Remember location in AML stream of address & length
26495b482a8SLen Brown 	 * operands since they need to be evaluated at run time.
26595b482a8SLen Brown 	 */
266849c2571SLv Zheng 	region_obj2 = acpi_ns_get_secondary_object(obj_desc);
26795b482a8SLen Brown 	region_obj2->extra.aml_start = aml_start;
26895b482a8SLen Brown 	region_obj2->extra.aml_length = aml_length;
269849c2571SLv Zheng 	region_obj2->extra.method_REG = NULL;
2708931d9eaSLin Ming 	if (walk_state->scope_info) {
2718931d9eaSLin Ming 		region_obj2->extra.scope_node =
2728931d9eaSLin Ming 		    walk_state->scope_info->scope.node;
2738931d9eaSLin Ming 	} else {
2748931d9eaSLin Ming 		region_obj2->extra.scope_node = node;
2758931d9eaSLin Ming 	}
27695b482a8SLen Brown 
27795b482a8SLen Brown 	/* Init the region from the operands */
27895b482a8SLen Brown 
279ec463666SBob Moore 	obj_desc->region.space_id = space_id;
28095b482a8SLen Brown 	obj_desc->region.address = 0;
28195b482a8SLen Brown 	obj_desc->region.length = 0;
282ca25f92bSJessica Clarke 	obj_desc->region.pointer = NULL;
28395b482a8SLen Brown 	obj_desc->region.node = node;
284849c2571SLv Zheng 	obj_desc->region.handler = NULL;
285849c2571SLv Zheng 	obj_desc->common.flags &=
286efaed9beSLv Zheng 	    ~(AOPOBJ_SETUP_COMPLETE | AOPOBJ_REG_CONNECTED |
287efaed9beSLv Zheng 	      AOPOBJ_OBJECT_INITIALIZED);
28895b482a8SLen Brown 
28995b482a8SLen Brown 	/* Install the new region object in the parent Node */
29095b482a8SLen Brown 
29195b482a8SLen Brown 	status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
29295b482a8SLen Brown 
29395b482a8SLen Brown cleanup:
29495b482a8SLen Brown 
29595b482a8SLen Brown 	/* Remove local reference to the object */
29695b482a8SLen Brown 
29795b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
29895b482a8SLen Brown 	return_ACPI_STATUS(status);
29995b482a8SLen Brown }
30095b482a8SLen Brown 
30195b482a8SLen Brown /*******************************************************************************
30295b482a8SLen Brown  *
30395b482a8SLen Brown  * FUNCTION:    acpi_ex_create_processor
30495b482a8SLen Brown  *
30595b482a8SLen Brown  * PARAMETERS:  walk_state          - Current state
30695b482a8SLen Brown  *
30795b482a8SLen Brown  * RETURN:      Status
30895b482a8SLen Brown  *
30995b482a8SLen Brown  * DESCRIPTION: Create a new processor object and populate the fields
31095b482a8SLen Brown  *
311ba494beeSBob Moore  *              Processor (Name[0], cpu_ID[1], pblock_addr[2], pblock_length[3])
31295b482a8SLen Brown  *
31395b482a8SLen Brown  ******************************************************************************/
31495b482a8SLen Brown 
acpi_ex_create_processor(struct acpi_walk_state * walk_state)31595b482a8SLen Brown acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state)
31695b482a8SLen Brown {
31795b482a8SLen Brown 	union acpi_operand_object **operand = &walk_state->operands[0];
31895b482a8SLen Brown 	union acpi_operand_object *obj_desc;
31995b482a8SLen Brown 	acpi_status status;
32095b482a8SLen Brown 
32195b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ex_create_processor, walk_state);
32295b482a8SLen Brown 
32395b482a8SLen Brown 	/* Create the processor object */
32495b482a8SLen Brown 
32595b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_PROCESSOR);
32695b482a8SLen Brown 	if (!obj_desc) {
32795b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
32895b482a8SLen Brown 	}
32995b482a8SLen Brown 
33095b482a8SLen Brown 	/* Initialize the processor object from the operands */
33195b482a8SLen Brown 
33295b482a8SLen Brown 	obj_desc->processor.proc_id = (u8) operand[1]->integer.value;
33395b482a8SLen Brown 	obj_desc->processor.length = (u8) operand[3]->integer.value;
33495b482a8SLen Brown 	obj_desc->processor.address =
33595b482a8SLen Brown 	    (acpi_io_address)operand[2]->integer.value;
33695b482a8SLen Brown 
33795b482a8SLen Brown 	/* Install the processor object in the parent Node */
33895b482a8SLen Brown 
33995b482a8SLen Brown 	status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
34095b482a8SLen Brown 				       obj_desc, ACPI_TYPE_PROCESSOR);
34195b482a8SLen Brown 
34295b482a8SLen Brown 	/* Remove local reference to the object */
34395b482a8SLen Brown 
34495b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
34595b482a8SLen Brown 	return_ACPI_STATUS(status);
34695b482a8SLen Brown }
34795b482a8SLen Brown 
34895b482a8SLen Brown /*******************************************************************************
34995b482a8SLen Brown  *
35095b482a8SLen Brown  * FUNCTION:    acpi_ex_create_power_resource
35195b482a8SLen Brown  *
35295b482a8SLen Brown  * PARAMETERS:  walk_state          - Current state
35395b482a8SLen Brown  *
35495b482a8SLen Brown  * RETURN:      Status
35595b482a8SLen Brown  *
35695b482a8SLen Brown  * DESCRIPTION: Create a new power_resource object and populate the fields
35795b482a8SLen Brown  *
35895b482a8SLen Brown  *              power_resource (Name[0], system_level[1], resource_order[2])
35995b482a8SLen Brown  *
36095b482a8SLen Brown  ******************************************************************************/
36195b482a8SLen Brown 
acpi_ex_create_power_resource(struct acpi_walk_state * walk_state)36295b482a8SLen Brown acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state)
36395b482a8SLen Brown {
36495b482a8SLen Brown 	union acpi_operand_object **operand = &walk_state->operands[0];
36595b482a8SLen Brown 	acpi_status status;
36695b482a8SLen Brown 	union acpi_operand_object *obj_desc;
36795b482a8SLen Brown 
36895b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ex_create_power_resource, walk_state);
36995b482a8SLen Brown 
37095b482a8SLen Brown 	/* Create the power resource object */
37195b482a8SLen Brown 
37295b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_POWER);
37395b482a8SLen Brown 	if (!obj_desc) {
37495b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
37595b482a8SLen Brown 	}
37695b482a8SLen Brown 
37795b482a8SLen Brown 	/* Initialize the power object from the operands */
37895b482a8SLen Brown 
37995b482a8SLen Brown 	obj_desc->power_resource.system_level = (u8) operand[1]->integer.value;
38095b482a8SLen Brown 	obj_desc->power_resource.resource_order =
38195b482a8SLen Brown 	    (u16) operand[2]->integer.value;
38295b482a8SLen Brown 
38395b482a8SLen Brown 	/* Install the  power resource object in the parent Node */
38495b482a8SLen Brown 
38595b482a8SLen Brown 	status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
38695b482a8SLen Brown 				       obj_desc, ACPI_TYPE_POWER);
38795b482a8SLen Brown 
38895b482a8SLen Brown 	/* Remove local reference to the object */
38995b482a8SLen Brown 
39095b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
39195b482a8SLen Brown 	return_ACPI_STATUS(status);
39295b482a8SLen Brown }
39395b482a8SLen Brown 
39495b482a8SLen Brown /*******************************************************************************
39595b482a8SLen Brown  *
39695b482a8SLen Brown  * FUNCTION:    acpi_ex_create_method
39795b482a8SLen Brown  *
39895b482a8SLen Brown  * PARAMETERS:  aml_start       - First byte of the method's AML
39995b482a8SLen Brown  *              aml_length      - AML byte count for this method
40095b482a8SLen Brown  *              walk_state      - Current state
40195b482a8SLen Brown  *
40295b482a8SLen Brown  * RETURN:      Status
40395b482a8SLen Brown  *
40495b482a8SLen Brown  * DESCRIPTION: Create a new method object
40595b482a8SLen Brown  *
40695b482a8SLen Brown  ******************************************************************************/
40795b482a8SLen Brown 
40895b482a8SLen Brown acpi_status
acpi_ex_create_method(u8 * aml_start,u32 aml_length,struct acpi_walk_state * walk_state)40995b482a8SLen Brown acpi_ex_create_method(u8 * aml_start,
41095b482a8SLen Brown 		      u32 aml_length, struct acpi_walk_state *walk_state)
41195b482a8SLen Brown {
41295b482a8SLen Brown 	union acpi_operand_object **operand = &walk_state->operands[0];
41395b482a8SLen Brown 	union acpi_operand_object *obj_desc;
41495b482a8SLen Brown 	acpi_status status;
41595b482a8SLen Brown 	u8 method_flags;
41695b482a8SLen Brown 
41795b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ex_create_method, walk_state);
41895b482a8SLen Brown 
41995b482a8SLen Brown 	/* Create a new method object */
42095b482a8SLen Brown 
42195b482a8SLen Brown 	obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
42295b482a8SLen Brown 	if (!obj_desc) {
42395b482a8SLen Brown 		status = AE_NO_MEMORY;
42495b482a8SLen Brown 		goto exit;
42595b482a8SLen Brown 	}
42695b482a8SLen Brown 
42795b482a8SLen Brown 	/* Save the method's AML pointer and length  */
42895b482a8SLen Brown 
42995b482a8SLen Brown 	obj_desc->method.aml_start = aml_start;
43095b482a8SLen Brown 	obj_desc->method.aml_length = aml_length;
43107b9c912SLv Zheng 	obj_desc->method.node = operand[0];
43295b482a8SLen Brown 
43395b482a8SLen Brown 	/*
43426294842SLin Ming 	 * Disassemble the method flags. Split off the arg_count, Serialized
43526294842SLin Ming 	 * flag, and sync_level for efficiency.
43695b482a8SLen Brown 	 */
43795b482a8SLen Brown 	method_flags = (u8)operand[1]->integer.value;
4381fad8738SBob Moore 	obj_desc->method.param_count = (u8)
4391fad8738SBob Moore 	    (method_flags & AML_METHOD_ARG_COUNT);
44095b482a8SLen Brown 
44195b482a8SLen Brown 	/*
44295b482a8SLen Brown 	 * Get the sync_level. If method is serialized, a mutex will be
44395b482a8SLen Brown 	 * created for this method when it is parsed.
44495b482a8SLen Brown 	 */
44595b482a8SLen Brown 	if (method_flags & AML_METHOD_SERIALIZED) {
44626294842SLin Ming 		obj_desc->method.info_flags = ACPI_METHOD_SERIALIZED;
44726294842SLin Ming 
44895b482a8SLen Brown 		/*
44995b482a8SLen Brown 		 * ACPI 1.0: sync_level = 0
45095b482a8SLen Brown 		 * ACPI 2.0: sync_level = sync_level in method declaration
45195b482a8SLen Brown 		 */
45295b482a8SLen Brown 		obj_desc->method.sync_level = (u8)
453b2f7ddcfSLin Ming 		    ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4);
45495b482a8SLen Brown 	}
45595b482a8SLen Brown 
45695b482a8SLen Brown 	/* Attach the new object to the method Node */
45795b482a8SLen Brown 
45895b482a8SLen Brown 	status = acpi_ns_attach_object((struct acpi_namespace_node *)operand[0],
45995b482a8SLen Brown 				       obj_desc, ACPI_TYPE_METHOD);
46095b482a8SLen Brown 
46195b482a8SLen Brown 	/* Remove local reference to the object */
46295b482a8SLen Brown 
46395b482a8SLen Brown 	acpi_ut_remove_reference(obj_desc);
46495b482a8SLen Brown 
46595b482a8SLen Brown exit:
46695b482a8SLen Brown 	/* Remove a reference to the operand */
46795b482a8SLen Brown 
46895b482a8SLen Brown 	acpi_ut_remove_reference(operand[1]);
46995b482a8SLen Brown 	return_ACPI_STATUS(status);
47095b482a8SLen Brown }
471