162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/*******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: utdelete - object deletion and reference count utilities
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci ******************************************************************************/
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <acpi/acpi.h>
962306a36Sopenharmony_ci#include "accommon.h"
1062306a36Sopenharmony_ci#include "acinterp.h"
1162306a36Sopenharmony_ci#include "acnamesp.h"
1262306a36Sopenharmony_ci#include "acevents.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define _COMPONENT          ACPI_UTILITIES
1562306a36Sopenharmony_ciACPI_MODULE_NAME("utdelete")
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/* Local prototypes */
1862306a36Sopenharmony_cistatic void acpi_ut_delete_internal_obj(union acpi_operand_object *object);
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void
2162306a36Sopenharmony_ciacpi_ut_update_ref_count(union acpi_operand_object *object, u32 action);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*******************************************************************************
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * FUNCTION:    acpi_ut_delete_internal_obj
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * PARAMETERS:  object         - Object to be deleted
2862306a36Sopenharmony_ci *
2962306a36Sopenharmony_ci * RETURN:      None
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci * DESCRIPTION: Low level object deletion, after reference counts have been
3262306a36Sopenharmony_ci *              updated (All reference counts, including sub-objects!)
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci ******************************************************************************/
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	void *obj_pointer = NULL;
3962306a36Sopenharmony_ci	union acpi_operand_object *handler_desc;
4062306a36Sopenharmony_ci	union acpi_operand_object *second_desc;
4162306a36Sopenharmony_ci	union acpi_operand_object *next_desc;
4262306a36Sopenharmony_ci	union acpi_operand_object *start_desc;
4362306a36Sopenharmony_ci	union acpi_operand_object **last_obj_ptr;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (!object) {
4862306a36Sopenharmony_ci		return_VOID;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/*
5262306a36Sopenharmony_ci	 * Must delete or free any pointers within the object that are not
5362306a36Sopenharmony_ci	 * actual ACPI objects (for example, a raw buffer pointer).
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	switch (object->common.type) {
5662306a36Sopenharmony_ci	case ACPI_TYPE_STRING:
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
5962306a36Sopenharmony_ci				  "**** String %p, ptr %p\n", object,
6062306a36Sopenharmony_ci				  object->string.pointer));
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		/* Free the actual string buffer */
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci			/* But only if it is NOT a pointer into an ACPI table */
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci			obj_pointer = object->string.pointer;
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci		break;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	case ACPI_TYPE_BUFFER:
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
7562306a36Sopenharmony_ci				  "**** Buffer %p, ptr %p\n", object,
7662306a36Sopenharmony_ci				  object->buffer.pointer));
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		/* Free the actual buffer */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci			/* But only if it is NOT a pointer into an ACPI table */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci			obj_pointer = object->buffer.pointer;
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci		break;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	case ACPI_TYPE_PACKAGE:
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
9162306a36Sopenharmony_ci				  " **** Package of count %X\n",
9262306a36Sopenharmony_ci				  object->package.count));
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		/*
9562306a36Sopenharmony_ci		 * Elements of the package are not handled here, they are deleted
9662306a36Sopenharmony_ci		 * separately
9762306a36Sopenharmony_ci		 */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		/* Free the (variable length) element pointer array */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		obj_pointer = object->package.elements;
10262306a36Sopenharmony_ci		break;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		/*
10562306a36Sopenharmony_ci		 * These objects have a possible list of notify handlers.
10662306a36Sopenharmony_ci		 * Device object also may have a GPE block.
10762306a36Sopenharmony_ci		 */
10862306a36Sopenharmony_ci	case ACPI_TYPE_DEVICE:
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		if (object->device.gpe_block) {
11162306a36Sopenharmony_ci			(void)acpi_ev_delete_gpe_block(object->device.
11262306a36Sopenharmony_ci						       gpe_block);
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		ACPI_FALLTHROUGH;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	case ACPI_TYPE_PROCESSOR:
11862306a36Sopenharmony_ci	case ACPI_TYPE_THERMAL:
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		/* Walk the address handler list for this object */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		handler_desc = object->common_notify.handler;
12362306a36Sopenharmony_ci		while (handler_desc) {
12462306a36Sopenharmony_ci			next_desc = handler_desc->address_space.next;
12562306a36Sopenharmony_ci			acpi_ut_remove_reference(handler_desc);
12662306a36Sopenharmony_ci			handler_desc = next_desc;
12762306a36Sopenharmony_ci		}
12862306a36Sopenharmony_ci		break;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	case ACPI_TYPE_MUTEX:
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
13362306a36Sopenharmony_ci				  "***** Mutex %p, OS Mutex %p\n",
13462306a36Sopenharmony_ci				  object, object->mutex.os_mutex));
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		if (object == acpi_gbl_global_lock_mutex) {
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci			/* Global Lock has extra semaphore */
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci			(void)
14162306a36Sopenharmony_ci			    acpi_os_delete_semaphore
14262306a36Sopenharmony_ci			    (acpi_gbl_global_lock_semaphore);
14362306a36Sopenharmony_ci			acpi_gbl_global_lock_semaphore = NULL;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci			acpi_os_delete_mutex(object->mutex.os_mutex);
14662306a36Sopenharmony_ci			acpi_gbl_global_lock_mutex = NULL;
14762306a36Sopenharmony_ci		} else {
14862306a36Sopenharmony_ci			acpi_ex_unlink_mutex(object);
14962306a36Sopenharmony_ci			acpi_os_delete_mutex(object->mutex.os_mutex);
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	case ACPI_TYPE_EVENT:
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
15662306a36Sopenharmony_ci				  "***** Event %p, OS Semaphore %p\n",
15762306a36Sopenharmony_ci				  object, object->event.os_semaphore));
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci		(void)acpi_os_delete_semaphore(object->event.os_semaphore);
16062306a36Sopenharmony_ci		object->event.os_semaphore = NULL;
16162306a36Sopenharmony_ci		break;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	case ACPI_TYPE_METHOD:
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
16662306a36Sopenharmony_ci				  "***** Method %p\n", object));
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		/* Delete the method mutex if it exists */
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		if (object->method.mutex) {
17162306a36Sopenharmony_ci			acpi_os_delete_mutex(object->method.mutex->mutex.
17262306a36Sopenharmony_ci					     os_mutex);
17362306a36Sopenharmony_ci			acpi_ut_delete_object_desc(object->method.mutex);
17462306a36Sopenharmony_ci			object->method.mutex = NULL;
17562306a36Sopenharmony_ci		}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		if (object->method.node) {
17862306a36Sopenharmony_ci			object->method.node = NULL;
17962306a36Sopenharmony_ci		}
18062306a36Sopenharmony_ci		break;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	case ACPI_TYPE_REGION:
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
18562306a36Sopenharmony_ci				  "***** Region %p\n", object));
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		/*
18862306a36Sopenharmony_ci		 * Update address_range list. However, only permanent regions
18962306a36Sopenharmony_ci		 * are installed in this list. (Not created within a method)
19062306a36Sopenharmony_ci		 */
19162306a36Sopenharmony_ci		if (!(object->region.node->flags & ANOBJ_TEMPORARY)) {
19262306a36Sopenharmony_ci			acpi_ut_remove_address_range(object->region.space_id,
19362306a36Sopenharmony_ci						     object->region.node);
19462306a36Sopenharmony_ci		}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		second_desc = acpi_ns_get_secondary_object(object);
19762306a36Sopenharmony_ci		if (second_desc) {
19862306a36Sopenharmony_ci			/*
19962306a36Sopenharmony_ci			 * Free the region_context if and only if the handler is one of the
20062306a36Sopenharmony_ci			 * default handlers -- and therefore, we created the context object
20162306a36Sopenharmony_ci			 * locally, it was not created by an external caller.
20262306a36Sopenharmony_ci			 */
20362306a36Sopenharmony_ci			handler_desc = object->region.handler;
20462306a36Sopenharmony_ci			if (handler_desc) {
20562306a36Sopenharmony_ci				next_desc =
20662306a36Sopenharmony_ci				    handler_desc->address_space.region_list;
20762306a36Sopenharmony_ci				start_desc = next_desc;
20862306a36Sopenharmony_ci				last_obj_ptr =
20962306a36Sopenharmony_ci				    &handler_desc->address_space.region_list;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci				/* Remove the region object from the handler list */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci				while (next_desc) {
21462306a36Sopenharmony_ci					if (next_desc == object) {
21562306a36Sopenharmony_ci						*last_obj_ptr =
21662306a36Sopenharmony_ci						    next_desc->region.next;
21762306a36Sopenharmony_ci						break;
21862306a36Sopenharmony_ci					}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci					/* Walk the linked list of handlers */
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci					last_obj_ptr = &next_desc->region.next;
22362306a36Sopenharmony_ci					next_desc = next_desc->region.next;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci					/* Prevent infinite loop if list is corrupted */
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci					if (next_desc == start_desc) {
22862306a36Sopenharmony_ci						ACPI_ERROR((AE_INFO,
22962306a36Sopenharmony_ci							    "Circular region list in address handler object %p",
23062306a36Sopenharmony_ci							    handler_desc));
23162306a36Sopenharmony_ci						return_VOID;
23262306a36Sopenharmony_ci					}
23362306a36Sopenharmony_ci				}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci				if (handler_desc->address_space.handler_flags &
23662306a36Sopenharmony_ci				    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci					/* Deactivate region and free region context */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci					if (handler_desc->address_space.setup) {
24162306a36Sopenharmony_ci						(void)handler_desc->
24262306a36Sopenharmony_ci						    address_space.setup(object,
24362306a36Sopenharmony_ci									ACPI_REGION_DEACTIVATE,
24462306a36Sopenharmony_ci									handler_desc->
24562306a36Sopenharmony_ci									address_space.
24662306a36Sopenharmony_ci									context,
24762306a36Sopenharmony_ci									&second_desc->
24862306a36Sopenharmony_ci									extra.
24962306a36Sopenharmony_ci									region_context);
25062306a36Sopenharmony_ci					}
25162306a36Sopenharmony_ci				}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci				acpi_ut_remove_reference(handler_desc);
25462306a36Sopenharmony_ci			}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci			/* Now we can free the Extra object */
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci			acpi_ut_delete_object_desc(second_desc);
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		if (object->field.internal_pcc_buffer) {
26162306a36Sopenharmony_ci			ACPI_FREE(object->field.internal_pcc_buffer);
26262306a36Sopenharmony_ci		}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci		break;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	case ACPI_TYPE_BUFFER_FIELD:
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
26962306a36Sopenharmony_ci				  "***** Buffer Field %p\n", object));
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		second_desc = acpi_ns_get_secondary_object(object);
27262306a36Sopenharmony_ci		if (second_desc) {
27362306a36Sopenharmony_ci			acpi_ut_delete_object_desc(second_desc);
27462306a36Sopenharmony_ci		}
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	case ACPI_TYPE_LOCAL_BANK_FIELD:
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
28062306a36Sopenharmony_ci				  "***** Bank Field %p\n", object));
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		second_desc = acpi_ns_get_secondary_object(object);
28362306a36Sopenharmony_ci		if (second_desc) {
28462306a36Sopenharmony_ci			acpi_ut_delete_object_desc(second_desc);
28562306a36Sopenharmony_ci		}
28662306a36Sopenharmony_ci		break;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
29162306a36Sopenharmony_ci				  "***** Address handler %p\n", object));
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci		acpi_os_delete_mutex(object->address_space.context_mutex);
29462306a36Sopenharmony_ci		break;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	default:
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		break;
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	/* Free any allocated memory (pointer within the object) found above */
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (obj_pointer) {
30462306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
30562306a36Sopenharmony_ci				  "Deleting Object Subptr %p\n", obj_pointer));
30662306a36Sopenharmony_ci		ACPI_FREE(obj_pointer);
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/* Now the object can be safely deleted */
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
31262306a36Sopenharmony_ci			      "%s: Deleting Object %p [%s]\n",
31362306a36Sopenharmony_ci			      ACPI_GET_FUNCTION_NAME, object,
31462306a36Sopenharmony_ci			      acpi_ut_get_object_type_name(object)));
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	acpi_ut_delete_object_desc(object);
31762306a36Sopenharmony_ci	return_VOID;
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci/*******************************************************************************
32162306a36Sopenharmony_ci *
32262306a36Sopenharmony_ci * FUNCTION:    acpi_ut_delete_internal_object_list
32362306a36Sopenharmony_ci *
32462306a36Sopenharmony_ci * PARAMETERS:  obj_list        - Pointer to the list to be deleted
32562306a36Sopenharmony_ci *
32662306a36Sopenharmony_ci * RETURN:      None
32762306a36Sopenharmony_ci *
32862306a36Sopenharmony_ci * DESCRIPTION: This function deletes an internal object list, including both
32962306a36Sopenharmony_ci *              simple objects and package objects
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci ******************************************************************************/
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_civoid acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	union acpi_operand_object **internal_obj;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	ACPI_FUNCTION_ENTRY();
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* Walk the null-terminated internal list */
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	for (internal_obj = obj_list; *internal_obj; internal_obj++) {
34262306a36Sopenharmony_ci		acpi_ut_remove_reference(*internal_obj);
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Free the combined parameter pointer list and object array */
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	ACPI_FREE(obj_list);
34862306a36Sopenharmony_ci	return;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*******************************************************************************
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * FUNCTION:    acpi_ut_update_ref_count
35462306a36Sopenharmony_ci *
35562306a36Sopenharmony_ci * PARAMETERS:  object          - Object whose ref count is to be updated
35662306a36Sopenharmony_ci *              action          - What to do (REF_INCREMENT or REF_DECREMENT)
35762306a36Sopenharmony_ci *
35862306a36Sopenharmony_ci * RETURN:      None. Sets new reference count within the object
35962306a36Sopenharmony_ci *
36062306a36Sopenharmony_ci * DESCRIPTION: Modify the reference count for an internal acpi object
36162306a36Sopenharmony_ci *
36262306a36Sopenharmony_ci ******************************************************************************/
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void
36562306a36Sopenharmony_ciacpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	u16 original_count;
36862306a36Sopenharmony_ci	u16 new_count = 0;
36962306a36Sopenharmony_ci	acpi_cpu_flags lock_flags;
37062306a36Sopenharmony_ci	char *message;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_update_ref_count);
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (!object) {
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	/*
37962306a36Sopenharmony_ci	 * Always get the reference count lock. Note: Interpreter and/or
38062306a36Sopenharmony_ci	 * Namespace is not always locked when this function is called.
38162306a36Sopenharmony_ci	 */
38262306a36Sopenharmony_ci	lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
38362306a36Sopenharmony_ci	original_count = object->common.reference_count;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* Perform the reference count action (increment, decrement) */
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	switch (action) {
38862306a36Sopenharmony_ci	case REF_INCREMENT:
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci		new_count = original_count + 1;
39162306a36Sopenharmony_ci		object->common.reference_count = new_count;
39262306a36Sopenharmony_ci		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		/* The current reference count should never be zero here */
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		if (!original_count) {
39762306a36Sopenharmony_ci			ACPI_WARNING((AE_INFO,
39862306a36Sopenharmony_ci				      "Obj %p, Reference Count was zero before increment\n",
39962306a36Sopenharmony_ci				      object));
40062306a36Sopenharmony_ci		}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
40362306a36Sopenharmony_ci				  "Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n",
40462306a36Sopenharmony_ci				  object, object->common.type,
40562306a36Sopenharmony_ci				  acpi_ut_get_object_type_name(object),
40662306a36Sopenharmony_ci				  new_count));
40762306a36Sopenharmony_ci		message = "Incremement";
40862306a36Sopenharmony_ci		break;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	case REF_DECREMENT:
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		/* The current reference count must be non-zero */
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		if (original_count) {
41562306a36Sopenharmony_ci			new_count = original_count - 1;
41662306a36Sopenharmony_ci			object->common.reference_count = new_count;
41762306a36Sopenharmony_ci		}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		if (!original_count) {
42262306a36Sopenharmony_ci			ACPI_WARNING((AE_INFO,
42362306a36Sopenharmony_ci				      "Obj %p, Reference Count is already zero, cannot decrement\n",
42462306a36Sopenharmony_ci				      object));
42562306a36Sopenharmony_ci			return;
42662306a36Sopenharmony_ci		}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
42962306a36Sopenharmony_ci				      "%s: Obj %p Type %.2X Refs %.2X [Decremented]\n",
43062306a36Sopenharmony_ci				      ACPI_GET_FUNCTION_NAME, object,
43162306a36Sopenharmony_ci				      object->common.type, new_count));
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci		/* Actually delete the object on a reference count of zero */
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci		if (new_count == 0) {
43662306a36Sopenharmony_ci			acpi_ut_delete_internal_obj(object);
43762306a36Sopenharmony_ci		}
43862306a36Sopenharmony_ci		message = "Decrement";
43962306a36Sopenharmony_ci		break;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	default:
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
44462306a36Sopenharmony_ci		ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
44562306a36Sopenharmony_ci			    action));
44662306a36Sopenharmony_ci		return;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * Sanity check the reference count, for debug purposes only.
45162306a36Sopenharmony_ci	 * (A deleted object will have a huge reference count)
45262306a36Sopenharmony_ci	 */
45362306a36Sopenharmony_ci	if (new_count > ACPI_MAX_REFERENCE_COUNT) {
45462306a36Sopenharmony_ci		ACPI_WARNING((AE_INFO,
45562306a36Sopenharmony_ci			      "Large Reference Count (0x%X) in object %p, Type=0x%.2X Operation=%s",
45662306a36Sopenharmony_ci			      new_count, object, object->common.type, message));
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci/*******************************************************************************
46162306a36Sopenharmony_ci *
46262306a36Sopenharmony_ci * FUNCTION:    acpi_ut_update_object_reference
46362306a36Sopenharmony_ci *
46462306a36Sopenharmony_ci * PARAMETERS:  object              - Increment or decrement the ref count for
46562306a36Sopenharmony_ci *                                    this object and all sub-objects
46662306a36Sopenharmony_ci *              action              - Either REF_INCREMENT or REF_DECREMENT
46762306a36Sopenharmony_ci *
46862306a36Sopenharmony_ci * RETURN:      Status
46962306a36Sopenharmony_ci *
47062306a36Sopenharmony_ci * DESCRIPTION: Increment or decrement the object reference count
47162306a36Sopenharmony_ci *
47262306a36Sopenharmony_ci * Object references are incremented when:
47362306a36Sopenharmony_ci * 1) An object is attached to a Node (namespace object)
47462306a36Sopenharmony_ci * 2) An object is copied (all subobjects must be incremented)
47562306a36Sopenharmony_ci *
47662306a36Sopenharmony_ci * Object references are decremented when:
47762306a36Sopenharmony_ci * 1) An object is detached from an Node
47862306a36Sopenharmony_ci *
47962306a36Sopenharmony_ci ******************************************************************************/
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ciacpi_status
48262306a36Sopenharmony_ciacpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	acpi_status status = AE_OK;
48562306a36Sopenharmony_ci	union acpi_generic_state *state_list = NULL;
48662306a36Sopenharmony_ci	union acpi_operand_object *next_object = NULL;
48762306a36Sopenharmony_ci	union acpi_operand_object *prev_object;
48862306a36Sopenharmony_ci	union acpi_generic_state *state;
48962306a36Sopenharmony_ci	u32 i;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_update_object_reference);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	while (object) {
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		/* Make sure that this isn't a namespace handle */
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci		if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
49862306a36Sopenharmony_ci			ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
49962306a36Sopenharmony_ci					  "Object %p is NS handle\n", object));
50062306a36Sopenharmony_ci			return (AE_OK);
50162306a36Sopenharmony_ci		}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		/*
50462306a36Sopenharmony_ci		 * All sub-objects must have their reference count updated
50562306a36Sopenharmony_ci		 * also. Different object types have different subobjects.
50662306a36Sopenharmony_ci		 */
50762306a36Sopenharmony_ci		switch (object->common.type) {
50862306a36Sopenharmony_ci		case ACPI_TYPE_DEVICE:
50962306a36Sopenharmony_ci		case ACPI_TYPE_PROCESSOR:
51062306a36Sopenharmony_ci		case ACPI_TYPE_POWER:
51162306a36Sopenharmony_ci		case ACPI_TYPE_THERMAL:
51262306a36Sopenharmony_ci			/*
51362306a36Sopenharmony_ci			 * Update the notify objects for these types (if present)
51462306a36Sopenharmony_ci			 * Two lists, system and device notify handlers.
51562306a36Sopenharmony_ci			 */
51662306a36Sopenharmony_ci			for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
51762306a36Sopenharmony_ci				prev_object =
51862306a36Sopenharmony_ci				    object->common_notify.notify_list[i];
51962306a36Sopenharmony_ci				while (prev_object) {
52062306a36Sopenharmony_ci					next_object =
52162306a36Sopenharmony_ci					    prev_object->notify.next[i];
52262306a36Sopenharmony_ci					acpi_ut_update_ref_count(prev_object,
52362306a36Sopenharmony_ci								 action);
52462306a36Sopenharmony_ci					prev_object = next_object;
52562306a36Sopenharmony_ci				}
52662306a36Sopenharmony_ci			}
52762306a36Sopenharmony_ci			break;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci		case ACPI_TYPE_PACKAGE:
53062306a36Sopenharmony_ci			/*
53162306a36Sopenharmony_ci			 * We must update all the sub-objects of the package,
53262306a36Sopenharmony_ci			 * each of whom may have their own sub-objects.
53362306a36Sopenharmony_ci			 */
53462306a36Sopenharmony_ci			for (i = 0; i < object->package.count; i++) {
53562306a36Sopenharmony_ci				/*
53662306a36Sopenharmony_ci				 * Null package elements are legal and can be simply
53762306a36Sopenharmony_ci				 * ignored.
53862306a36Sopenharmony_ci				 */
53962306a36Sopenharmony_ci				next_object = object->package.elements[i];
54062306a36Sopenharmony_ci				if (!next_object) {
54162306a36Sopenharmony_ci					continue;
54262306a36Sopenharmony_ci				}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci				switch (next_object->common.type) {
54562306a36Sopenharmony_ci				case ACPI_TYPE_INTEGER:
54662306a36Sopenharmony_ci				case ACPI_TYPE_STRING:
54762306a36Sopenharmony_ci				case ACPI_TYPE_BUFFER:
54862306a36Sopenharmony_ci					/*
54962306a36Sopenharmony_ci					 * For these very simple sub-objects, we can just
55062306a36Sopenharmony_ci					 * update the reference count here and continue.
55162306a36Sopenharmony_ci					 * Greatly increases performance of this operation.
55262306a36Sopenharmony_ci					 */
55362306a36Sopenharmony_ci					acpi_ut_update_ref_count(next_object,
55462306a36Sopenharmony_ci								 action);
55562306a36Sopenharmony_ci					break;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci				default:
55862306a36Sopenharmony_ci					/*
55962306a36Sopenharmony_ci					 * For complex sub-objects, push them onto the stack
56062306a36Sopenharmony_ci					 * for later processing (this eliminates recursion.)
56162306a36Sopenharmony_ci					 */
56262306a36Sopenharmony_ci					status =
56362306a36Sopenharmony_ci					    acpi_ut_create_update_state_and_push
56462306a36Sopenharmony_ci					    (next_object, action, &state_list);
56562306a36Sopenharmony_ci					if (ACPI_FAILURE(status)) {
56662306a36Sopenharmony_ci						goto error_exit;
56762306a36Sopenharmony_ci					}
56862306a36Sopenharmony_ci					break;
56962306a36Sopenharmony_ci				}
57062306a36Sopenharmony_ci			}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci			next_object = NULL;
57362306a36Sopenharmony_ci			break;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		case ACPI_TYPE_BUFFER_FIELD:
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci			next_object = object->buffer_field.buffer_obj;
57862306a36Sopenharmony_ci			break;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		case ACPI_TYPE_LOCAL_BANK_FIELD:
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci			next_object = object->bank_field.bank_obj;
58362306a36Sopenharmony_ci			status =
58462306a36Sopenharmony_ci			    acpi_ut_create_update_state_and_push(object->
58562306a36Sopenharmony_ci								 bank_field.
58662306a36Sopenharmony_ci								 region_obj,
58762306a36Sopenharmony_ci								 action,
58862306a36Sopenharmony_ci								 &state_list);
58962306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
59062306a36Sopenharmony_ci				goto error_exit;
59162306a36Sopenharmony_ci			}
59262306a36Sopenharmony_ci			break;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci		case ACPI_TYPE_LOCAL_INDEX_FIELD:
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci			next_object = object->index_field.index_obj;
59762306a36Sopenharmony_ci			status =
59862306a36Sopenharmony_ci			    acpi_ut_create_update_state_and_push(object->
59962306a36Sopenharmony_ci								 index_field.
60062306a36Sopenharmony_ci								 data_obj,
60162306a36Sopenharmony_ci								 action,
60262306a36Sopenharmony_ci								 &state_list);
60362306a36Sopenharmony_ci			if (ACPI_FAILURE(status)) {
60462306a36Sopenharmony_ci				goto error_exit;
60562306a36Sopenharmony_ci			}
60662306a36Sopenharmony_ci			break;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci		case ACPI_TYPE_LOCAL_REFERENCE:
60962306a36Sopenharmony_ci			/*
61062306a36Sopenharmony_ci			 * The target of an Index (a package, string, or buffer) or a named
61162306a36Sopenharmony_ci			 * reference must track changes to the ref count of the index or
61262306a36Sopenharmony_ci			 * target object.
61362306a36Sopenharmony_ci			 */
61462306a36Sopenharmony_ci			if ((object->reference.class == ACPI_REFCLASS_INDEX) ||
61562306a36Sopenharmony_ci			    (object->reference.class == ACPI_REFCLASS_NAME)) {
61662306a36Sopenharmony_ci				next_object = object->reference.object;
61762306a36Sopenharmony_ci			}
61862306a36Sopenharmony_ci			break;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		case ACPI_TYPE_LOCAL_REGION_FIELD:
62162306a36Sopenharmony_ci		case ACPI_TYPE_REGION:
62262306a36Sopenharmony_ci		default:
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci			break;	/* No subobjects for all other types */
62562306a36Sopenharmony_ci		}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci		/*
62862306a36Sopenharmony_ci		 * Now we can update the count in the main object. This can only
62962306a36Sopenharmony_ci		 * happen after we update the sub-objects in case this causes the
63062306a36Sopenharmony_ci		 * main object to be deleted.
63162306a36Sopenharmony_ci		 */
63262306a36Sopenharmony_ci		acpi_ut_update_ref_count(object, action);
63362306a36Sopenharmony_ci		object = NULL;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci		/* Move on to the next object to be updated */
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci		if (next_object) {
63862306a36Sopenharmony_ci			object = next_object;
63962306a36Sopenharmony_ci			next_object = NULL;
64062306a36Sopenharmony_ci		} else if (state_list) {
64162306a36Sopenharmony_ci			state = acpi_ut_pop_generic_state(&state_list);
64262306a36Sopenharmony_ci			object = state->update.object;
64362306a36Sopenharmony_ci			acpi_ut_delete_generic_state(state);
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci	}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	return (AE_OK);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_cierror_exit:
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	ACPI_EXCEPTION((AE_INFO, status,
65262306a36Sopenharmony_ci			"Could not update object reference count"));
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	/* Free any stacked Update State objects */
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	while (state_list) {
65762306a36Sopenharmony_ci		state = acpi_ut_pop_generic_state(&state_list);
65862306a36Sopenharmony_ci		acpi_ut_delete_generic_state(state);
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	return (status);
66262306a36Sopenharmony_ci}
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci/*******************************************************************************
66562306a36Sopenharmony_ci *
66662306a36Sopenharmony_ci * FUNCTION:    acpi_ut_add_reference
66762306a36Sopenharmony_ci *
66862306a36Sopenharmony_ci * PARAMETERS:  object          - Object whose reference count is to be
66962306a36Sopenharmony_ci *                                incremented
67062306a36Sopenharmony_ci *
67162306a36Sopenharmony_ci * RETURN:      None
67262306a36Sopenharmony_ci *
67362306a36Sopenharmony_ci * DESCRIPTION: Add one reference to an ACPI object
67462306a36Sopenharmony_ci *
67562306a36Sopenharmony_ci ******************************************************************************/
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_civoid acpi_ut_add_reference(union acpi_operand_object *object)
67862306a36Sopenharmony_ci{
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_add_reference);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* Ensure that we have a valid object */
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	if (!acpi_ut_valid_internal_object(object)) {
68562306a36Sopenharmony_ci		return;
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
68962306a36Sopenharmony_ci			  "Obj %p Current Refs=%X [To Be Incremented]\n",
69062306a36Sopenharmony_ci			  object, object->common.reference_count));
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	/* Increment the reference count */
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	(void)acpi_ut_update_object_reference(object, REF_INCREMENT);
69562306a36Sopenharmony_ci	return;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci/*******************************************************************************
69962306a36Sopenharmony_ci *
70062306a36Sopenharmony_ci * FUNCTION:    acpi_ut_remove_reference
70162306a36Sopenharmony_ci *
70262306a36Sopenharmony_ci * PARAMETERS:  object         - Object whose ref count will be decremented
70362306a36Sopenharmony_ci *
70462306a36Sopenharmony_ci * RETURN:      None
70562306a36Sopenharmony_ci *
70662306a36Sopenharmony_ci * DESCRIPTION: Decrement the reference count of an ACPI internal object
70762306a36Sopenharmony_ci *
70862306a36Sopenharmony_ci ******************************************************************************/
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_civoid acpi_ut_remove_reference(union acpi_operand_object *object)
71162306a36Sopenharmony_ci{
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ut_remove_reference);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/*
71662306a36Sopenharmony_ci	 * Allow a NULL pointer to be passed in, just ignore it. This saves
71762306a36Sopenharmony_ci	 * each caller from having to check. Also, ignore NS nodes.
71862306a36Sopenharmony_ci	 */
71962306a36Sopenharmony_ci	if (!object ||
72062306a36Sopenharmony_ci	    (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
72162306a36Sopenharmony_ci		return;
72262306a36Sopenharmony_ci	}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Ensure that we have a valid object */
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (!acpi_ut_valid_internal_object(object)) {
72762306a36Sopenharmony_ci		return;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
73162306a36Sopenharmony_ci			      "%s: Obj %p Current Refs=%X [To Be Decremented]\n",
73262306a36Sopenharmony_ci			      ACPI_GET_FUNCTION_NAME, object,
73362306a36Sopenharmony_ci			      object->common.reference_count));
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/*
73662306a36Sopenharmony_ci	 * Decrement the reference count, and only actually delete the object
73762306a36Sopenharmony_ci	 * if the reference count becomes 0. (Must also decrement the ref count
73862306a36Sopenharmony_ci	 * of all subobjects!)
73962306a36Sopenharmony_ci	 */
74062306a36Sopenharmony_ci	(void)acpi_ut_update_object_reference(object, REF_DECREMENT);
74162306a36Sopenharmony_ci	return;
74262306a36Sopenharmony_ci}
743