xref: /linux/drivers/acpi/acpica/utdelete.c (revision 1cdfe9e3)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /*******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: utdelete - object deletion and reference count utilities
595b482a8SLen Brown  *
695b482a8SLen Brown  ******************************************************************************/
795b482a8SLen Brown 
895b482a8SLen Brown #include <acpi/acpi.h>
9e2f7a777SLen Brown #include "accommon.h"
10e2f7a777SLen Brown #include "acinterp.h"
11e2f7a777SLen Brown #include "acnamesp.h"
12e2f7a777SLen Brown #include "acevents.h"
1395b482a8SLen Brown 
1495b482a8SLen Brown #define _COMPONENT          ACPI_UTILITIES
1595b482a8SLen Brown ACPI_MODULE_NAME("utdelete")
1695b482a8SLen Brown 
1795b482a8SLen Brown /* Local prototypes */
1895b482a8SLen Brown static void acpi_ut_delete_internal_obj(union acpi_operand_object *object);
1995b482a8SLen Brown 
2095b482a8SLen Brown static void
2195b482a8SLen Brown acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action);
2295b482a8SLen Brown 
2395b482a8SLen Brown /*******************************************************************************
2495b482a8SLen Brown  *
2595b482a8SLen Brown  * FUNCTION:    acpi_ut_delete_internal_obj
2695b482a8SLen Brown  *
27ba494beeSBob Moore  * PARAMETERS:  object         - Object to be deleted
2895b482a8SLen Brown  *
2995b482a8SLen Brown  * RETURN:      None
3095b482a8SLen Brown  *
3195b482a8SLen Brown  * DESCRIPTION: Low level object deletion, after reference counts have been
3295b482a8SLen Brown  *              updated (All reference counts, including sub-objects!)
3395b482a8SLen Brown  *
3495b482a8SLen Brown  ******************************************************************************/
3595b482a8SLen Brown 
acpi_ut_delete_internal_obj(union acpi_operand_object * object)3695b482a8SLen Brown static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
3795b482a8SLen Brown {
3895b482a8SLen Brown 	void *obj_pointer = NULL;
3995b482a8SLen Brown 	union acpi_operand_object *handler_desc;
4095b482a8SLen Brown 	union acpi_operand_object *second_desc;
4195b482a8SLen Brown 	union acpi_operand_object *next_desc;
42f953529fSBob Moore 	union acpi_operand_object *start_desc;
433362a6baSLin Ming 	union acpi_operand_object **last_obj_ptr;
4495b482a8SLen Brown 
4595b482a8SLen Brown 	ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object);
4695b482a8SLen Brown 
4795b482a8SLen Brown 	if (!object) {
4895b482a8SLen Brown 		return_VOID;
4995b482a8SLen Brown 	}
5095b482a8SLen Brown 
5195b482a8SLen Brown 	/*
5295b482a8SLen Brown 	 * Must delete or free any pointers within the object that are not
5395b482a8SLen Brown 	 * actual ACPI objects (for example, a raw buffer pointer).
5495b482a8SLen Brown 	 */
553371c19cSBob Moore 	switch (object->common.type) {
5695b482a8SLen Brown 	case ACPI_TYPE_STRING:
5795b482a8SLen Brown 
5895b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
5995b482a8SLen Brown 				  "**** String %p, ptr %p\n", object,
6095b482a8SLen Brown 				  object->string.pointer));
6195b482a8SLen Brown 
6295b482a8SLen Brown 		/* Free the actual string buffer */
6395b482a8SLen Brown 
6495b482a8SLen Brown 		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
6595b482a8SLen Brown 
6695b482a8SLen Brown 			/* But only if it is NOT a pointer into an ACPI table */
6795b482a8SLen Brown 
6895b482a8SLen Brown 			obj_pointer = object->string.pointer;
6995b482a8SLen Brown 		}
7095b482a8SLen Brown 		break;
7195b482a8SLen Brown 
7295b482a8SLen Brown 	case ACPI_TYPE_BUFFER:
7395b482a8SLen Brown 
7495b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
7595b482a8SLen Brown 				  "**** Buffer %p, ptr %p\n", object,
7695b482a8SLen Brown 				  object->buffer.pointer));
7795b482a8SLen Brown 
7895b482a8SLen Brown 		/* Free the actual buffer */
7995b482a8SLen Brown 
8095b482a8SLen Brown 		if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
8195b482a8SLen Brown 
8295b482a8SLen Brown 			/* But only if it is NOT a pointer into an ACPI table */
8395b482a8SLen Brown 
8495b482a8SLen Brown 			obj_pointer = object->buffer.pointer;
8595b482a8SLen Brown 		}
8695b482a8SLen Brown 		break;
8795b482a8SLen Brown 
8895b482a8SLen Brown 	case ACPI_TYPE_PACKAGE:
8995b482a8SLen Brown 
9095b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
9195b482a8SLen Brown 				  " **** Package of count %X\n",
9295b482a8SLen Brown 				  object->package.count));
9395b482a8SLen Brown 
9495b482a8SLen Brown 		/*
9595b482a8SLen Brown 		 * Elements of the package are not handled here, they are deleted
9695b482a8SLen Brown 		 * separately
9795b482a8SLen Brown 		 */
9895b482a8SLen Brown 
9995b482a8SLen Brown 		/* Free the (variable length) element pointer array */
10095b482a8SLen Brown 
10195b482a8SLen Brown 		obj_pointer = object->package.elements;
10295b482a8SLen Brown 		break;
10395b482a8SLen Brown 
10495b482a8SLen Brown 		/*
10595b482a8SLen Brown 		 * These objects have a possible list of notify handlers.
10695b482a8SLen Brown 		 * Device object also may have a GPE block.
10795b482a8SLen Brown 		 */
10895b482a8SLen Brown 	case ACPI_TYPE_DEVICE:
10995b482a8SLen Brown 
11095b482a8SLen Brown 		if (object->device.gpe_block) {
11195b482a8SLen Brown 			(void)acpi_ev_delete_gpe_block(object->device.
11295b482a8SLen Brown 						       gpe_block);
11395b482a8SLen Brown 		}
11495b482a8SLen Brown 
115c1a7c2ceSNick Desaulniers 		ACPI_FALLTHROUGH;
11695b482a8SLen Brown 
11795b482a8SLen Brown 	case ACPI_TYPE_PROCESSOR:
11895b482a8SLen Brown 	case ACPI_TYPE_THERMAL:
11995b482a8SLen Brown 
12086ed4bc8SBob Moore 		/* Walk the address handler list for this object */
12195b482a8SLen Brown 
12295b482a8SLen Brown 		handler_desc = object->common_notify.handler;
12395b482a8SLen Brown 		while (handler_desc) {
12495b482a8SLen Brown 			next_desc = handler_desc->address_space.next;
12595b482a8SLen Brown 			acpi_ut_remove_reference(handler_desc);
12695b482a8SLen Brown 			handler_desc = next_desc;
12795b482a8SLen Brown 		}
12895b482a8SLen Brown 		break;
12995b482a8SLen Brown 
13095b482a8SLen Brown 	case ACPI_TYPE_MUTEX:
13195b482a8SLen Brown 
13295b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
13395b482a8SLen Brown 				  "***** Mutex %p, OS Mutex %p\n",
13495b482a8SLen Brown 				  object, object->mutex.os_mutex));
13595b482a8SLen Brown 
13695b482a8SLen Brown 		if (object == acpi_gbl_global_lock_mutex) {
13795b482a8SLen Brown 
13895b482a8SLen Brown 			/* Global Lock has extra semaphore */
13995b482a8SLen Brown 
14095b482a8SLen Brown 			(void)
14195b482a8SLen Brown 			    acpi_os_delete_semaphore
14295b482a8SLen Brown 			    (acpi_gbl_global_lock_semaphore);
14395b482a8SLen Brown 			acpi_gbl_global_lock_semaphore = NULL;
14495b482a8SLen Brown 
14595b482a8SLen Brown 			acpi_os_delete_mutex(object->mutex.os_mutex);
14695b482a8SLen Brown 			acpi_gbl_global_lock_mutex = NULL;
14795b482a8SLen Brown 		} else {
14895b482a8SLen Brown 			acpi_ex_unlink_mutex(object);
14995b482a8SLen Brown 			acpi_os_delete_mutex(object->mutex.os_mutex);
15095b482a8SLen Brown 		}
15195b482a8SLen Brown 		break;
15295b482a8SLen Brown 
15395b482a8SLen Brown 	case ACPI_TYPE_EVENT:
15495b482a8SLen Brown 
15595b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
15695b482a8SLen Brown 				  "***** Event %p, OS Semaphore %p\n",
15795b482a8SLen Brown 				  object, object->event.os_semaphore));
15895b482a8SLen Brown 
15995b482a8SLen Brown 		(void)acpi_os_delete_semaphore(object->event.os_semaphore);
16095b482a8SLen Brown 		object->event.os_semaphore = NULL;
16195b482a8SLen Brown 		break;
16295b482a8SLen Brown 
16395b482a8SLen Brown 	case ACPI_TYPE_METHOD:
16495b482a8SLen Brown 
16595b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
16695b482a8SLen Brown 				  "***** Method %p\n", object));
16795b482a8SLen Brown 
16895b482a8SLen Brown 		/* Delete the method mutex if it exists */
16995b482a8SLen Brown 
17095b482a8SLen Brown 		if (object->method.mutex) {
17195b482a8SLen Brown 			acpi_os_delete_mutex(object->method.mutex->mutex.
17295b482a8SLen Brown 					     os_mutex);
17395b482a8SLen Brown 			acpi_ut_delete_object_desc(object->method.mutex);
17495b482a8SLen Brown 			object->method.mutex = NULL;
17595b482a8SLen Brown 		}
1761fad8738SBob Moore 
17707b9c912SLv Zheng 		if (object->method.node) {
17807b9c912SLv Zheng 			object->method.node = NULL;
17907b9c912SLv Zheng 		}
18095b482a8SLen Brown 		break;
18195b482a8SLen Brown 
18295b482a8SLen Brown 	case ACPI_TYPE_REGION:
18395b482a8SLen Brown 
18495b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
18595b482a8SLen Brown 				  "***** Region %p\n", object));
18695b482a8SLen Brown 
187f654c0feSLin Ming 		/*
188f654c0feSLin Ming 		 * Update address_range list. However, only permanent regions
189f654c0feSLin Ming 		 * are installed in this list. (Not created within a method)
190f654c0feSLin Ming 		 */
191f654c0feSLin Ming 		if (!(object->region.node->flags & ANOBJ_TEMPORARY)) {
192f654c0feSLin Ming 			acpi_ut_remove_address_range(object->region.space_id,
193f654c0feSLin Ming 						     object->region.node);
194f654c0feSLin Ming 		}
195a5fe1a03SLin Ming 
19695b482a8SLen Brown 		second_desc = acpi_ns_get_secondary_object(object);
19795b482a8SLen Brown 		if (second_desc) {
19895b482a8SLen Brown 			/*
19995b482a8SLen Brown 			 * Free the region_context if and only if the handler is one of the
20095b482a8SLen Brown 			 * default handlers -- and therefore, we created the context object
20195b482a8SLen Brown 			 * locally, it was not created by an external caller.
20295b482a8SLen Brown 			 */
20395b482a8SLen Brown 			handler_desc = object->region.handler;
20495b482a8SLen Brown 			if (handler_desc) {
2053362a6baSLin Ming 				next_desc =
2063362a6baSLin Ming 				    handler_desc->address_space.region_list;
207f953529fSBob Moore 				start_desc = next_desc;
2083362a6baSLin Ming 				last_obj_ptr =
2093362a6baSLin Ming 				    &handler_desc->address_space.region_list;
2103362a6baSLin Ming 
211f953529fSBob Moore 				/* Remove the region object from the handler list */
2123362a6baSLin Ming 
2133362a6baSLin Ming 				while (next_desc) {
2143362a6baSLin Ming 					if (next_desc == object) {
2153362a6baSLin Ming 						*last_obj_ptr =
2163362a6baSLin Ming 						    next_desc->region.next;
2173362a6baSLin Ming 						break;
2183362a6baSLin Ming 					}
2193362a6baSLin Ming 
220f953529fSBob Moore 					/* Walk the linked list of handlers */
2213362a6baSLin Ming 
2223362a6baSLin Ming 					last_obj_ptr = &next_desc->region.next;
2233362a6baSLin Ming 					next_desc = next_desc->region.next;
224f953529fSBob Moore 
225f953529fSBob Moore 					/* Prevent infinite loop if list is corrupted */
226f953529fSBob Moore 
227f953529fSBob Moore 					if (next_desc == start_desc) {
228f953529fSBob Moore 						ACPI_ERROR((AE_INFO,
229f953529fSBob Moore 							    "Circular region list in address handler object %p",
230f953529fSBob Moore 							    handler_desc));
231f953529fSBob Moore 						return_VOID;
232f953529fSBob Moore 					}
2333362a6baSLin Ming 				}
2343362a6baSLin Ming 
23595b482a8SLen Brown 				if (handler_desc->address_space.handler_flags &
23695b482a8SLen Brown 				    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
23795b482a8SLen Brown 
23895b482a8SLen Brown 					/* Deactivate region and free region context */
23995b482a8SLen Brown 
24095b482a8SLen Brown 					if (handler_desc->address_space.setup) {
24195b482a8SLen Brown 						(void)handler_desc->
24295b482a8SLen Brown 						    address_space.setup(object,
24395b482a8SLen Brown 									ACPI_REGION_DEACTIVATE,
24495b482a8SLen Brown 									handler_desc->
24595b482a8SLen Brown 									address_space.
24695b482a8SLen Brown 									context,
24795b482a8SLen Brown 									&second_desc->
24895b482a8SLen Brown 									extra.
24995b482a8SLen Brown 									region_context);
25095b482a8SLen Brown 					}
25195b482a8SLen Brown 				}
25295b482a8SLen Brown 
25395b482a8SLen Brown 				acpi_ut_remove_reference(handler_desc);
25495b482a8SLen Brown 			}
25595b482a8SLen Brown 
25695b482a8SLen Brown 			/* Now we can free the Extra object */
25795b482a8SLen Brown 
25895b482a8SLen Brown 			acpi_ut_delete_object_desc(second_desc);
25995b482a8SLen Brown 		}
260aa6ec56bSErik Schmauss 		if (object->field.internal_pcc_buffer) {
261aa6ec56bSErik Schmauss 			ACPI_FREE(object->field.internal_pcc_buffer);
262aa6ec56bSErik Schmauss 		}
263aa6ec56bSErik Schmauss 
26495b482a8SLen Brown 		break;
26595b482a8SLen Brown 
26695b482a8SLen Brown 	case ACPI_TYPE_BUFFER_FIELD:
26795b482a8SLen Brown 
26895b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
26995b482a8SLen Brown 				  "***** Buffer Field %p\n", object));
27095b482a8SLen Brown 
27195b482a8SLen Brown 		second_desc = acpi_ns_get_secondary_object(object);
27295b482a8SLen Brown 		if (second_desc) {
27395b482a8SLen Brown 			acpi_ut_delete_object_desc(second_desc);
27495b482a8SLen Brown 		}
27595b482a8SLen Brown 		break;
27695b482a8SLen Brown 
27795b482a8SLen Brown 	case ACPI_TYPE_LOCAL_BANK_FIELD:
27895b482a8SLen Brown 
27995b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
28095b482a8SLen Brown 				  "***** Bank Field %p\n", object));
28195b482a8SLen Brown 
28295b482a8SLen Brown 		second_desc = acpi_ns_get_secondary_object(object);
28395b482a8SLen Brown 		if (second_desc) {
28495b482a8SLen Brown 			acpi_ut_delete_object_desc(second_desc);
28595b482a8SLen Brown 		}
28695b482a8SLen Brown 		break;
28795b482a8SLen Brown 
288e4dfe108SErik Kaneda 	case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
289e4dfe108SErik Kaneda 
290e4dfe108SErik Kaneda 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
291e4dfe108SErik Kaneda 				  "***** Address handler %p\n", object));
292e4dfe108SErik Kaneda 
293e4dfe108SErik Kaneda 		acpi_os_delete_mutex(object->address_space.context_mutex);
294e4dfe108SErik Kaneda 		break;
295e4dfe108SErik Kaneda 
29695b482a8SLen Brown 	default:
2971d1ea1b7SChao Guan 
29895b482a8SLen Brown 		break;
29995b482a8SLen Brown 	}
30095b482a8SLen Brown 
30195b482a8SLen Brown 	/* Free any allocated memory (pointer within the object) found above */
30295b482a8SLen Brown 
30395b482a8SLen Brown 	if (obj_pointer) {
30495b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
30595b482a8SLen Brown 				  "Deleting Object Subptr %p\n", obj_pointer));
30695b482a8SLen Brown 		ACPI_FREE(obj_pointer);
30795b482a8SLen Brown 	}
30895b482a8SLen Brown 
30995b482a8SLen Brown 	/* Now the object can be safely deleted */
31095b482a8SLen Brown 
3111ef63231SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
3121ef63231SBob Moore 			      "%s: Deleting Object %p [%s]\n",
3131ef63231SBob Moore 			      ACPI_GET_FUNCTION_NAME, object,
3141ef63231SBob Moore 			      acpi_ut_get_object_type_name(object)));
31595b482a8SLen Brown 
31695b482a8SLen Brown 	acpi_ut_delete_object_desc(object);
31795b482a8SLen Brown 	return_VOID;
31895b482a8SLen Brown }
31995b482a8SLen Brown 
32095b482a8SLen Brown /*******************************************************************************
32195b482a8SLen Brown  *
32295b482a8SLen Brown  * FUNCTION:    acpi_ut_delete_internal_object_list
32395b482a8SLen Brown  *
32495b482a8SLen Brown  * PARAMETERS:  obj_list        - Pointer to the list to be deleted
32595b482a8SLen Brown  *
32695b482a8SLen Brown  * RETURN:      None
32795b482a8SLen Brown  *
32895b482a8SLen Brown  * DESCRIPTION: This function deletes an internal object list, including both
32995b482a8SLen Brown  *              simple objects and package objects
33095b482a8SLen Brown  *
33195b482a8SLen Brown  ******************************************************************************/
33295b482a8SLen Brown 
acpi_ut_delete_internal_object_list(union acpi_operand_object ** obj_list)33395b482a8SLen Brown void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
33495b482a8SLen Brown {
33595b482a8SLen Brown 	union acpi_operand_object **internal_obj;
33695b482a8SLen Brown 
337c8d586f8SBob Moore 	ACPI_FUNCTION_ENTRY();
33895b482a8SLen Brown 
33995b482a8SLen Brown 	/* Walk the null-terminated internal list */
34095b482a8SLen Brown 
34195b482a8SLen Brown 	for (internal_obj = obj_list; *internal_obj; internal_obj++) {
34295b482a8SLen Brown 		acpi_ut_remove_reference(*internal_obj);
34395b482a8SLen Brown 	}
34495b482a8SLen Brown 
34595b482a8SLen Brown 	/* Free the combined parameter pointer list and object array */
34695b482a8SLen Brown 
34795b482a8SLen Brown 	ACPI_FREE(obj_list);
3480e770b32SBob Moore 	return;
34995b482a8SLen Brown }
35095b482a8SLen Brown 
35195b482a8SLen Brown /*******************************************************************************
35295b482a8SLen Brown  *
35395b482a8SLen Brown  * FUNCTION:    acpi_ut_update_ref_count
35495b482a8SLen Brown  *
355ba494beeSBob Moore  * PARAMETERS:  object          - Object whose ref count is to be updated
35658892c96SBob Moore  *              action          - What to do (REF_INCREMENT or REF_DECREMENT)
35795b482a8SLen Brown  *
35858892c96SBob Moore  * RETURN:      None. Sets new reference count within the object
35995b482a8SLen Brown  *
36058892c96SBob Moore  * DESCRIPTION: Modify the reference count for an internal acpi object
36195b482a8SLen Brown  *
36295b482a8SLen Brown  ******************************************************************************/
36395b482a8SLen Brown 
36495b482a8SLen Brown static void
acpi_ut_update_ref_count(union acpi_operand_object * object,u32 action)36595b482a8SLen Brown acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
36695b482a8SLen Brown {
36758892c96SBob Moore 	u16 original_count;
36858892c96SBob Moore 	u16 new_count = 0;
36958892c96SBob Moore 	acpi_cpu_flags lock_flags;
370ff5340f8SErik Schmauss 	char *message;
37195b482a8SLen Brown 
37295b482a8SLen Brown 	ACPI_FUNCTION_NAME(ut_update_ref_count);
37395b482a8SLen Brown 
37495b482a8SLen Brown 	if (!object) {
37595b482a8SLen Brown 		return;
37695b482a8SLen Brown 	}
37795b482a8SLen Brown 
37895b482a8SLen Brown 	/*
37958892c96SBob Moore 	 * Always get the reference count lock. Note: Interpreter and/or
38058892c96SBob Moore 	 * Namespace is not always locked when this function is called.
38195b482a8SLen Brown 	 */
38258892c96SBob Moore 	lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
38358892c96SBob Moore 	original_count = object->common.reference_count;
38458892c96SBob Moore 
38558892c96SBob Moore 	/* Perform the reference count action (increment, decrement) */
38658892c96SBob Moore 
38795b482a8SLen Brown 	switch (action) {
38895b482a8SLen Brown 	case REF_INCREMENT:
38995b482a8SLen Brown 
39058892c96SBob Moore 		new_count = original_count + 1;
39195b482a8SLen Brown 		object->common.reference_count = new_count;
39258892c96SBob Moore 		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
39358892c96SBob Moore 
39458892c96SBob Moore 		/* The current reference count should never be zero here */
39558892c96SBob Moore 
39658892c96SBob Moore 		if (!original_count) {
39758892c96SBob Moore 			ACPI_WARNING((AE_INFO,
39858892c96SBob Moore 				      "Obj %p, Reference Count was zero before increment\n",
39958892c96SBob Moore 				      object));
40058892c96SBob Moore 		}
40195b482a8SLen Brown 
40295b482a8SLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
4037225d046SBob Moore 				  "Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n",
4047225d046SBob Moore 				  object, object->common.type,
4057225d046SBob Moore 				  acpi_ut_get_object_type_name(object),
4067225d046SBob Moore 				  new_count));
407ff5340f8SErik Schmauss 		message = "Incremement";
40895b482a8SLen Brown 		break;
40995b482a8SLen Brown 
41095b482a8SLen Brown 	case REF_DECREMENT:
41195b482a8SLen Brown 
41258892c96SBob Moore 		/* The current reference count must be non-zero */
41395b482a8SLen Brown 
41458892c96SBob Moore 		if (original_count) {
41558892c96SBob Moore 			new_count = original_count - 1;
41695b482a8SLen Brown 			object->common.reference_count = new_count;
41758892c96SBob Moore 		}
41858892c96SBob Moore 
41958892c96SBob Moore 		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
42058892c96SBob Moore 
42158892c96SBob Moore 		if (!original_count) {
42258892c96SBob Moore 			ACPI_WARNING((AE_INFO,
42358892c96SBob Moore 				      "Obj %p, Reference Count is already zero, cannot decrement\n",
42458892c96SBob Moore 				      object));
425*1cdfe9e3SRafael J. Wysocki 			return;
42658892c96SBob Moore 		}
42758892c96SBob Moore 
4281ef63231SBob Moore 		ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
4291ef63231SBob Moore 				      "%s: Obj %p Type %.2X Refs %.2X [Decremented]\n",
4301ef63231SBob Moore 				      ACPI_GET_FUNCTION_NAME, object,
4311ef63231SBob Moore 				      object->common.type, new_count));
43258892c96SBob Moore 
43358892c96SBob Moore 		/* Actually delete the object on a reference count of zero */
43458892c96SBob Moore 
43595b482a8SLen Brown 		if (new_count == 0) {
43695b482a8SLen Brown 			acpi_ut_delete_internal_obj(object);
43795b482a8SLen Brown 		}
438ff5340f8SErik Schmauss 		message = "Decrement";
43995b482a8SLen Brown 		break;
44095b482a8SLen Brown 
44195b482a8SLen Brown 	default:
44295b482a8SLen Brown 
44358892c96SBob Moore 		acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
44458892c96SBob Moore 		ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
44558892c96SBob Moore 			    action));
44658892c96SBob Moore 		return;
44795b482a8SLen Brown 	}
44895b482a8SLen Brown 
44995b482a8SLen Brown 	/*
45095b482a8SLen Brown 	 * Sanity check the reference count, for debug purposes only.
45195b482a8SLen Brown 	 * (A deleted object will have a huge reference count)
45295b482a8SLen Brown 	 */
45358892c96SBob Moore 	if (new_count > ACPI_MAX_REFERENCE_COUNT) {
45495b482a8SLen Brown 		ACPI_WARNING((AE_INFO,
455ff5340f8SErik Schmauss 			      "Large Reference Count (0x%X) in object %p, Type=0x%.2X Operation=%s",
456ff5340f8SErik Schmauss 			      new_count, object, object->common.type, message));
45795b482a8SLen Brown 	}
45895b482a8SLen Brown }
45995b482a8SLen Brown 
46095b482a8SLen Brown /*******************************************************************************
46195b482a8SLen Brown  *
46295b482a8SLen Brown  * FUNCTION:    acpi_ut_update_object_reference
46395b482a8SLen Brown  *
4649a1ae804SBob Moore  * PARAMETERS:  object              - Increment or decrement the ref count for
4659a1ae804SBob Moore  *                                    this object and all sub-objects
46660f3deb5SBob Moore  *              action              - Either REF_INCREMENT or REF_DECREMENT
46795b482a8SLen Brown  *
46895b482a8SLen Brown  * RETURN:      Status
46995b482a8SLen Brown  *
4709a1ae804SBob Moore  * DESCRIPTION: Increment or decrement the object reference count
47195b482a8SLen Brown  *
47295b482a8SLen Brown  * Object references are incremented when:
47395b482a8SLen Brown  * 1) An object is attached to a Node (namespace object)
47495b482a8SLen Brown  * 2) An object is copied (all subobjects must be incremented)
47595b482a8SLen Brown  *
47695b482a8SLen Brown  * Object references are decremented when:
47795b482a8SLen Brown  * 1) An object is detached from an Node
47895b482a8SLen Brown  *
47995b482a8SLen Brown  ******************************************************************************/
48095b482a8SLen Brown 
48195b482a8SLen Brown acpi_status
acpi_ut_update_object_reference(union acpi_operand_object * object,u16 action)48295b482a8SLen Brown acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
48395b482a8SLen Brown {
48495b482a8SLen Brown 	acpi_status status = AE_OK;
48595b482a8SLen Brown 	union acpi_generic_state *state_list = NULL;
48695b482a8SLen Brown 	union acpi_operand_object *next_object = NULL;
48786ed4bc8SBob Moore 	union acpi_operand_object *prev_object;
48895b482a8SLen Brown 	union acpi_generic_state *state;
48995b482a8SLen Brown 	u32 i;
49095b482a8SLen Brown 
4910e770b32SBob Moore 	ACPI_FUNCTION_NAME(ut_update_object_reference);
49295b482a8SLen Brown 
49395b482a8SLen Brown 	while (object) {
49495b482a8SLen Brown 
49595b482a8SLen Brown 		/* Make sure that this isn't a namespace handle */
49695b482a8SLen Brown 
49795b482a8SLen Brown 		if (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED) {
49895b482a8SLen Brown 			ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
49995b482a8SLen Brown 					  "Object %p is NS handle\n", object));
5000e770b32SBob Moore 			return (AE_OK);
50195b482a8SLen Brown 		}
50295b482a8SLen Brown 
50395b482a8SLen Brown 		/*
5049a1ae804SBob Moore 		 * All sub-objects must have their reference count updated
5051fad8738SBob Moore 		 * also. Different object types have different subobjects.
50695b482a8SLen Brown 		 */
5073371c19cSBob Moore 		switch (object->common.type) {
50895b482a8SLen Brown 		case ACPI_TYPE_DEVICE:
50995b482a8SLen Brown 		case ACPI_TYPE_PROCESSOR:
51095b482a8SLen Brown 		case ACPI_TYPE_POWER:
51195b482a8SLen Brown 		case ACPI_TYPE_THERMAL:
51286ed4bc8SBob Moore 			/*
51386ed4bc8SBob Moore 			 * Update the notify objects for these types (if present)
51486ed4bc8SBob Moore 			 * Two lists, system and device notify handlers.
51586ed4bc8SBob Moore 			 */
51686ed4bc8SBob Moore 			for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
51786ed4bc8SBob Moore 				prev_object =
51886ed4bc8SBob Moore 				    object->common_notify.notify_list[i];
51986ed4bc8SBob Moore 				while (prev_object) {
52086ed4bc8SBob Moore 					next_object =
52186ed4bc8SBob Moore 					    prev_object->notify.next[i];
52286ed4bc8SBob Moore 					acpi_ut_update_ref_count(prev_object,
52386ed4bc8SBob Moore 								 action);
52486ed4bc8SBob Moore 					prev_object = next_object;
52586ed4bc8SBob Moore 				}
52686ed4bc8SBob Moore 			}
52795b482a8SLen Brown 			break;
52895b482a8SLen Brown 
52995b482a8SLen Brown 		case ACPI_TYPE_PACKAGE:
53095b482a8SLen Brown 			/*
53195b482a8SLen Brown 			 * We must update all the sub-objects of the package,
53295b482a8SLen Brown 			 * each of whom may have their own sub-objects.
53395b482a8SLen Brown 			 */
53495b482a8SLen Brown 			for (i = 0; i < object->package.count; i++) {
53595b482a8SLen Brown 				/*
53653938551SChao Guan 				 * Null package elements are legal and can be simply
53753938551SChao Guan 				 * ignored.
53853938551SChao Guan 				 */
53953938551SChao Guan 				next_object = object->package.elements[i];
54053938551SChao Guan 				if (!next_object) {
54153938551SChao Guan 					continue;
54253938551SChao Guan 				}
54353938551SChao Guan 
54453938551SChao Guan 				switch (next_object->common.type) {
54553938551SChao Guan 				case ACPI_TYPE_INTEGER:
54653938551SChao Guan 				case ACPI_TYPE_STRING:
54753938551SChao Guan 				case ACPI_TYPE_BUFFER:
54853938551SChao Guan 					/*
54953938551SChao Guan 					 * For these very simple sub-objects, we can just
55053938551SChao Guan 					 * update the reference count here and continue.
55153938551SChao Guan 					 * Greatly increases performance of this operation.
55253938551SChao Guan 					 */
55353938551SChao Guan 					acpi_ut_update_ref_count(next_object,
55453938551SChao Guan 								 action);
55553938551SChao Guan 					break;
55653938551SChao Guan 
55753938551SChao Guan 				default:
55853938551SChao Guan 					/*
55953938551SChao Guan 					 * For complex sub-objects, push them onto the stack
56053938551SChao Guan 					 * for later processing (this eliminates recursion.)
56195b482a8SLen Brown 					 */
56295b482a8SLen Brown 					status =
56395b482a8SLen Brown 					    acpi_ut_create_update_state_and_push
56453938551SChao Guan 					    (next_object, action, &state_list);
56595b482a8SLen Brown 					if (ACPI_FAILURE(status)) {
56695b482a8SLen Brown 						goto error_exit;
56795b482a8SLen Brown 					}
56853938551SChao Guan 					break;
56995b482a8SLen Brown 				}
57053938551SChao Guan 			}
5719a1ae804SBob Moore 
57253938551SChao Guan 			next_object = NULL;
57395b482a8SLen Brown 			break;
57495b482a8SLen Brown 
57595b482a8SLen Brown 		case ACPI_TYPE_BUFFER_FIELD:
57695b482a8SLen Brown 
57795b482a8SLen Brown 			next_object = object->buffer_field.buffer_obj;
57895b482a8SLen Brown 			break;
57995b482a8SLen Brown 
58095b482a8SLen Brown 		case ACPI_TYPE_LOCAL_BANK_FIELD:
58195b482a8SLen Brown 
58295b482a8SLen Brown 			next_object = object->bank_field.bank_obj;
58395b482a8SLen Brown 			status =
58495b482a8SLen Brown 			    acpi_ut_create_update_state_and_push(object->
58595b482a8SLen Brown 								 bank_field.
58695b482a8SLen Brown 								 region_obj,
58795b482a8SLen Brown 								 action,
58895b482a8SLen Brown 								 &state_list);
58995b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
59095b482a8SLen Brown 				goto error_exit;
59195b482a8SLen Brown 			}
59295b482a8SLen Brown 			break;
59395b482a8SLen Brown 
59495b482a8SLen Brown 		case ACPI_TYPE_LOCAL_INDEX_FIELD:
59595b482a8SLen Brown 
59695b482a8SLen Brown 			next_object = object->index_field.index_obj;
59795b482a8SLen Brown 			status =
59895b482a8SLen Brown 			    acpi_ut_create_update_state_and_push(object->
59995b482a8SLen Brown 								 index_field.
60095b482a8SLen Brown 								 data_obj,
60195b482a8SLen Brown 								 action,
60295b482a8SLen Brown 								 &state_list);
60395b482a8SLen Brown 			if (ACPI_FAILURE(status)) {
60495b482a8SLen Brown 				goto error_exit;
60595b482a8SLen Brown 			}
60695b482a8SLen Brown 			break;
60795b482a8SLen Brown 
60895b482a8SLen Brown 		case ACPI_TYPE_LOCAL_REFERENCE:
60995b482a8SLen Brown 			/*
61095b482a8SLen Brown 			 * The target of an Index (a package, string, or buffer) or a named
61195b482a8SLen Brown 			 * reference must track changes to the ref count of the index or
61295b482a8SLen Brown 			 * target object.
61395b482a8SLen Brown 			 */
61495b482a8SLen Brown 			if ((object->reference.class == ACPI_REFCLASS_INDEX) ||
61595b482a8SLen Brown 			    (object->reference.class == ACPI_REFCLASS_NAME)) {
61695b482a8SLen Brown 				next_object = object->reference.object;
61795b482a8SLen Brown 			}
61895b482a8SLen Brown 			break;
61995b482a8SLen Brown 
6206a54ebaeSErik Kaneda 		case ACPI_TYPE_LOCAL_REGION_FIELD:
62195b482a8SLen Brown 		case ACPI_TYPE_REGION:
62295b482a8SLen Brown 		default:
6231d1ea1b7SChao Guan 
62495b482a8SLen Brown 			break;	/* No subobjects for all other types */
62595b482a8SLen Brown 		}
62695b482a8SLen Brown 
62795b482a8SLen Brown 		/*
62895b482a8SLen Brown 		 * Now we can update the count in the main object. This can only
62995b482a8SLen Brown 		 * happen after we update the sub-objects in case this causes the
63095b482a8SLen Brown 		 * main object to be deleted.
63195b482a8SLen Brown 		 */
63295b482a8SLen Brown 		acpi_ut_update_ref_count(object, action);
63395b482a8SLen Brown 		object = NULL;
63495b482a8SLen Brown 
63595b482a8SLen Brown 		/* Move on to the next object to be updated */
63695b482a8SLen Brown 
63795b482a8SLen Brown 		if (next_object) {
63895b482a8SLen Brown 			object = next_object;
63995b482a8SLen Brown 			next_object = NULL;
64095b482a8SLen Brown 		} else if (state_list) {
64195b482a8SLen Brown 			state = acpi_ut_pop_generic_state(&state_list);
64295b482a8SLen Brown 			object = state->update.object;
64395b482a8SLen Brown 			acpi_ut_delete_generic_state(state);
64495b482a8SLen Brown 		}
64595b482a8SLen Brown 	}
64695b482a8SLen Brown 
6470e770b32SBob Moore 	return (AE_OK);
64895b482a8SLen Brown 
64995b482a8SLen Brown error_exit:
65095b482a8SLen Brown 
65195b482a8SLen Brown 	ACPI_EXCEPTION((AE_INFO, status,
65295b482a8SLen Brown 			"Could not update object reference count"));
65395b482a8SLen Brown 
65495b482a8SLen Brown 	/* Free any stacked Update State objects */
65595b482a8SLen Brown 
65695b482a8SLen Brown 	while (state_list) {
65795b482a8SLen Brown 		state = acpi_ut_pop_generic_state(&state_list);
65895b482a8SLen Brown 		acpi_ut_delete_generic_state(state);
65995b482a8SLen Brown 	}
66095b482a8SLen Brown 
6610e770b32SBob Moore 	return (status);
66295b482a8SLen Brown }
66395b482a8SLen Brown 
66495b482a8SLen Brown /*******************************************************************************
66595b482a8SLen Brown  *
66695b482a8SLen Brown  * FUNCTION:    acpi_ut_add_reference
66795b482a8SLen Brown  *
668ba494beeSBob Moore  * PARAMETERS:  object          - Object whose reference count is to be
66995b482a8SLen Brown  *                                incremented
67095b482a8SLen Brown  *
67195b482a8SLen Brown  * RETURN:      None
67295b482a8SLen Brown  *
67395b482a8SLen Brown  * DESCRIPTION: Add one reference to an ACPI object
67495b482a8SLen Brown  *
67595b482a8SLen Brown  ******************************************************************************/
67695b482a8SLen Brown 
acpi_ut_add_reference(union acpi_operand_object * object)67795b482a8SLen Brown void acpi_ut_add_reference(union acpi_operand_object *object)
67895b482a8SLen Brown {
67995b482a8SLen Brown 
6800e770b32SBob Moore 	ACPI_FUNCTION_NAME(ut_add_reference);
68195b482a8SLen Brown 
68295b482a8SLen Brown 	/* Ensure that we have a valid object */
68395b482a8SLen Brown 
68495b482a8SLen Brown 	if (!acpi_ut_valid_internal_object(object)) {
6850e770b32SBob Moore 		return;
68695b482a8SLen Brown 	}
68795b482a8SLen Brown 
68895b482a8SLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
68995b482a8SLen Brown 			  "Obj %p Current Refs=%X [To Be Incremented]\n",
69095b482a8SLen Brown 			  object, object->common.reference_count));
69195b482a8SLen Brown 
69295b482a8SLen Brown 	/* Increment the reference count */
69395b482a8SLen Brown 
69495b482a8SLen Brown 	(void)acpi_ut_update_object_reference(object, REF_INCREMENT);
6950e770b32SBob Moore 	return;
69695b482a8SLen Brown }
69795b482a8SLen Brown 
69895b482a8SLen Brown /*******************************************************************************
69995b482a8SLen Brown  *
70095b482a8SLen Brown  * FUNCTION:    acpi_ut_remove_reference
70195b482a8SLen Brown  *
702ba494beeSBob Moore  * PARAMETERS:  object         - Object whose ref count will be decremented
70395b482a8SLen Brown  *
70495b482a8SLen Brown  * RETURN:      None
70595b482a8SLen Brown  *
70695b482a8SLen Brown  * DESCRIPTION: Decrement the reference count of an ACPI internal object
70795b482a8SLen Brown  *
70895b482a8SLen Brown  ******************************************************************************/
70995b482a8SLen Brown 
acpi_ut_remove_reference(union acpi_operand_object * object)71095b482a8SLen Brown void acpi_ut_remove_reference(union acpi_operand_object *object)
71195b482a8SLen Brown {
71295b482a8SLen Brown 
7130e770b32SBob Moore 	ACPI_FUNCTION_NAME(ut_remove_reference);
71495b482a8SLen Brown 
71595b482a8SLen Brown 	/*
71695b482a8SLen Brown 	 * Allow a NULL pointer to be passed in, just ignore it. This saves
71795b482a8SLen Brown 	 * each caller from having to check. Also, ignore NS nodes.
71895b482a8SLen Brown 	 */
71995b482a8SLen Brown 	if (!object ||
72095b482a8SLen Brown 	    (ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {
7210e770b32SBob Moore 		return;
72295b482a8SLen Brown 	}
72395b482a8SLen Brown 
72495b482a8SLen Brown 	/* Ensure that we have a valid object */
72595b482a8SLen Brown 
72695b482a8SLen Brown 	if (!acpi_ut_valid_internal_object(object)) {
7270e770b32SBob Moore 		return;
72895b482a8SLen Brown 	}
72995b482a8SLen Brown 
7301ef63231SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_ALLOCATIONS,
7311ef63231SBob Moore 			      "%s: Obj %p Current Refs=%X [To Be Decremented]\n",
7321ef63231SBob Moore 			      ACPI_GET_FUNCTION_NAME, object,
7331ef63231SBob Moore 			      object->common.reference_count));
73495b482a8SLen Brown 
73595b482a8SLen Brown 	/*
73695b482a8SLen Brown 	 * Decrement the reference count, and only actually delete the object
73795b482a8SLen Brown 	 * if the reference count becomes 0. (Must also decrement the ref count
73895b482a8SLen Brown 	 * of all subobjects!)
73995b482a8SLen Brown 	 */
74095b482a8SLen Brown 	(void)acpi_ut_update_object_reference(object, REF_DECREMENT);
7410e770b32SBob Moore 	return;
74295b482a8SLen Brown }
743