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