1/*******************************************************************************
2 *
3 * Module Name: utdelete - object deletion and reference count utilities
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <contrib/dev/acpica/include/acpi.h>
45#include <contrib/dev/acpica/include/accommon.h>
46#include <contrib/dev/acpica/include/acinterp.h>
47#include <contrib/dev/acpica/include/acnamesp.h>
48#include <contrib/dev/acpica/include/acevents.h>
49
50
51#define _COMPONENT          ACPI_UTILITIES
52        ACPI_MODULE_NAME    ("utdelete")
53
54/* Local prototypes */
55
56static void
57AcpiUtDeleteInternalObj (
58    ACPI_OPERAND_OBJECT     *Object);
59
60static void
61AcpiUtUpdateRefCount (
62    ACPI_OPERAND_OBJECT     *Object,
63    UINT32                  Action);
64
65
66/*******************************************************************************
67 *
68 * FUNCTION:    AcpiUtDeleteInternalObj
69 *
70 * PARAMETERS:  Object         - Object to be deleted
71 *
72 * RETURN:      None
73 *
74 * DESCRIPTION: Low level object deletion, after reference counts have been
75 *              updated (All reference counts, including sub-objects!)
76 *
77 ******************************************************************************/
78
79static void
80AcpiUtDeleteInternalObj (
81    ACPI_OPERAND_OBJECT     *Object)
82{
83    void                    *ObjPointer = NULL;
84    ACPI_OPERAND_OBJECT     *HandlerDesc;
85    ACPI_OPERAND_OBJECT     *SecondDesc;
86    ACPI_OPERAND_OBJECT     *NextDesc;
87    ACPI_OPERAND_OBJECT     *StartDesc;
88    ACPI_OPERAND_OBJECT     **LastObjPtr;
89
90
91    ACPI_FUNCTION_TRACE_PTR (UtDeleteInternalObj, Object);
92
93
94    if (!Object)
95    {
96        return_VOID;
97    }
98
99    /*
100     * Must delete or free any pointers within the object that are not
101     * actual ACPI objects (for example, a raw buffer pointer).
102     */
103    switch (Object->Common.Type)
104    {
105    case ACPI_TYPE_STRING:
106
107        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n",
108            Object, Object->String.Pointer));
109
110        /* Free the actual string buffer */
111
112        if (!(Object->Common.Flags & AOPOBJ_STATIC_POINTER))
113        {
114            /* But only if it is NOT a pointer into an ACPI table */
115
116            ObjPointer = Object->String.Pointer;
117        }
118        break;
119
120    case ACPI_TYPE_BUFFER:
121
122        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n",
123            Object, Object->Buffer.Pointer));
124
125        /* Free the actual buffer */
126
127        if (!(Object->Common.Flags & AOPOBJ_STATIC_POINTER))
128        {
129            /* But only if it is NOT a pointer into an ACPI table */
130
131            ObjPointer = Object->Buffer.Pointer;
132        }
133        break;
134
135    case ACPI_TYPE_PACKAGE:
136
137        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n",
138            Object->Package.Count));
139
140        /*
141         * Elements of the package are not handled here, they are deleted
142         * separately
143         */
144
145        /* Free the (variable length) element pointer array */
146
147        ObjPointer = Object->Package.Elements;
148        break;
149
150    /*
151     * These objects have a possible list of notify handlers.
152     * Device object also may have a GPE block.
153     */
154    case ACPI_TYPE_DEVICE:
155
156        if (Object->Device.GpeBlock)
157        {
158            (void) AcpiEvDeleteGpeBlock (Object->Device.GpeBlock);
159        }
160
161        /*lint -fallthrough */
162
163    case ACPI_TYPE_PROCESSOR:
164    case ACPI_TYPE_THERMAL:
165
166        /* Walk the address handler list for this object */
167
168        HandlerDesc = Object->CommonNotify.Handler;
169        while (HandlerDesc)
170        {
171            NextDesc = HandlerDesc->AddressSpace.Next;
172            AcpiUtRemoveReference (HandlerDesc);
173            HandlerDesc = NextDesc;
174        }
175        break;
176
177    case ACPI_TYPE_MUTEX:
178
179        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
180            "***** Mutex %p, OS Mutex %p\n",
181            Object, Object->Mutex.OsMutex));
182
183        if (Object == AcpiGbl_GlobalLockMutex)
184        {
185            /* Global Lock has extra semaphore */
186
187            (void) AcpiOsDeleteSemaphore (AcpiGbl_GlobalLockSemaphore);
188            AcpiGbl_GlobalLockSemaphore = NULL;
189
190            AcpiOsDeleteMutex (Object->Mutex.OsMutex);
191            AcpiGbl_GlobalLockMutex = NULL;
192        }
193        else
194        {
195            AcpiExUnlinkMutex (Object);
196            AcpiOsDeleteMutex (Object->Mutex.OsMutex);
197        }
198        break;
199
200    case ACPI_TYPE_EVENT:
201
202        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
203            "***** Event %p, OS Semaphore %p\n",
204            Object, Object->Event.OsSemaphore));
205
206        (void) AcpiOsDeleteSemaphore (Object->Event.OsSemaphore);
207        Object->Event.OsSemaphore = NULL;
208        break;
209
210    case ACPI_TYPE_METHOD:
211
212        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
213            "***** Method %p\n", Object));
214
215        /* Delete the method mutex if it exists */
216
217        if (Object->Method.Mutex)
218        {
219            AcpiOsDeleteMutex (Object->Method.Mutex->Mutex.OsMutex);
220            AcpiUtDeleteObjectDesc (Object->Method.Mutex);
221            Object->Method.Mutex = NULL;
222        }
223
224        if (Object->Method.Node)
225        {
226            Object->Method.Node = NULL;
227        }
228        break;
229
230    case ACPI_TYPE_REGION:
231
232        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
233            "***** Region %p\n", Object));
234
235        /*
236         * Update AddressRange list. However, only permanent regions
237         * are installed in this list. (Not created within a method)
238         */
239        if (!(Object->Region.Node->Flags & ANOBJ_TEMPORARY))
240        {
241            AcpiUtRemoveAddressRange (Object->Region.SpaceId,
242                Object->Region.Node);
243        }
244
245        SecondDesc = AcpiNsGetSecondaryObject (Object);
246        if (SecondDesc)
247        {
248            /*
249             * Free the RegionContext if and only if the handler is one of the
250             * default handlers -- and therefore, we created the context object
251             * locally, it was not created by an external caller.
252             */
253            HandlerDesc = Object->Region.Handler;
254            if (HandlerDesc)
255            {
256                NextDesc = HandlerDesc->AddressSpace.RegionList;
257                StartDesc = NextDesc;
258                LastObjPtr = &HandlerDesc->AddressSpace.RegionList;
259
260                /* Remove the region object from the handler list */
261
262                while (NextDesc)
263                {
264                    if (NextDesc == Object)
265                    {
266                        *LastObjPtr = NextDesc->Region.Next;
267                        break;
268                    }
269
270                    /* Walk the linked list of handlers */
271
272                    LastObjPtr = &NextDesc->Region.Next;
273                    NextDesc = NextDesc->Region.Next;
274
275                    /* Prevent infinite loop if list is corrupted */
276
277                    if (NextDesc == StartDesc)
278                    {
279                        ACPI_ERROR ((AE_INFO,
280                            "Circular region list in address handler object %p",
281                            HandlerDesc));
282                        return_VOID;
283                    }
284                }
285
286                if (HandlerDesc->AddressSpace.HandlerFlags &
287                    ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)
288                {
289                    /* Deactivate region and free region context */
290
291                    if (HandlerDesc->AddressSpace.Setup)
292                    {
293                        (void) HandlerDesc->AddressSpace.Setup (Object,
294                            ACPI_REGION_DEACTIVATE,
295                            HandlerDesc->AddressSpace.Context,
296                            &SecondDesc->Extra.RegionContext);
297                    }
298                }
299
300                AcpiUtRemoveReference (HandlerDesc);
301            }
302
303            /* Now we can free the Extra object */
304
305            AcpiUtDeleteObjectDesc (SecondDesc);
306        }
307        break;
308
309    case ACPI_TYPE_BUFFER_FIELD:
310
311        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
312            "***** Buffer Field %p\n", Object));
313
314        SecondDesc = AcpiNsGetSecondaryObject (Object);
315        if (SecondDesc)
316        {
317            AcpiUtDeleteObjectDesc (SecondDesc);
318        }
319        break;
320
321    case ACPI_TYPE_LOCAL_BANK_FIELD:
322
323        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
324            "***** Bank Field %p\n", Object));
325
326        SecondDesc = AcpiNsGetSecondaryObject (Object);
327        if (SecondDesc)
328        {
329            AcpiUtDeleteObjectDesc (SecondDesc);
330        }
331        break;
332
333    default:
334
335        break;
336    }
337
338    /* Free any allocated memory (pointer within the object) found above */
339
340    if (ObjPointer)
341    {
342        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n",
343            ObjPointer));
344        ACPI_FREE (ObjPointer);
345    }
346
347    /* Now the object can be safely deleted */
348
349    ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n",
350        Object, AcpiUtGetObjectTypeName (Object)));
351
352    AcpiUtDeleteObjectDesc (Object);
353    return_VOID;
354}
355
356
357/*******************************************************************************
358 *
359 * FUNCTION:    AcpiUtDeleteInternalObjectList
360 *
361 * PARAMETERS:  ObjList         - Pointer to the list to be deleted
362 *
363 * RETURN:      None
364 *
365 * DESCRIPTION: This function deletes an internal object list, including both
366 *              simple objects and package objects
367 *
368 ******************************************************************************/
369
370void
371AcpiUtDeleteInternalObjectList (
372    ACPI_OPERAND_OBJECT     **ObjList)
373{
374    ACPI_OPERAND_OBJECT     **InternalObj;
375
376
377    ACPI_FUNCTION_ENTRY ();
378
379
380    /* Walk the null-terminated internal list */
381
382    for (InternalObj = ObjList; *InternalObj; InternalObj++)
383    {
384        AcpiUtRemoveReference (*InternalObj);
385    }
386
387    /* Free the combined parameter pointer list and object array */
388
389    ACPI_FREE (ObjList);
390    return;
391}
392
393
394/*******************************************************************************
395 *
396 * FUNCTION:    AcpiUtUpdateRefCount
397 *
398 * PARAMETERS:  Object          - Object whose ref count is to be updated
399 *              Action          - What to do (REF_INCREMENT or REF_DECREMENT)
400 *
401 * RETURN:      None. Sets new reference count within the object
402 *
403 * DESCRIPTION: Modify the reference count for an internal acpi object
404 *
405 ******************************************************************************/
406
407static void
408AcpiUtUpdateRefCount (
409    ACPI_OPERAND_OBJECT     *Object,
410    UINT32                  Action)
411{
412    UINT16                  OriginalCount;
413    UINT16                  NewCount = 0;
414    ACPI_CPU_FLAGS          LockFlags;
415
416
417    ACPI_FUNCTION_NAME (UtUpdateRefCount);
418
419
420    if (!Object)
421    {
422        return;
423    }
424
425    /*
426     * Always get the reference count lock. Note: Interpreter and/or
427     * Namespace is not always locked when this function is called.
428     */
429    LockFlags = AcpiOsAcquireLock (AcpiGbl_ReferenceCountLock);
430    OriginalCount = Object->Common.ReferenceCount;
431
432    /* Perform the reference count action (increment, decrement) */
433
434    switch (Action)
435    {
436    case REF_INCREMENT:
437
438        NewCount = OriginalCount + 1;
439        Object->Common.ReferenceCount = NewCount;
440        AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags);
441
442        /* The current reference count should never be zero here */
443
444        if (!OriginalCount)
445        {
446            ACPI_WARNING ((AE_INFO,
447                "Obj %p, Reference Count was zero before increment\n",
448                Object));
449        }
450
451        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
452            "Obj %p Type %.2X Refs %.2X [Incremented]\n",
453            Object, Object->Common.Type, NewCount));
454        break;
455
456    case REF_DECREMENT:
457
458        /* The current reference count must be non-zero */
459
460        if (OriginalCount)
461        {
462            NewCount = OriginalCount - 1;
463            Object->Common.ReferenceCount = NewCount;
464        }
465
466        AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags);
467
468        if (!OriginalCount)
469        {
470            ACPI_WARNING ((AE_INFO,
471                "Obj %p, Reference Count is already zero, cannot decrement\n",
472                Object));
473        }
474
475        ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
476            "Obj %p Type %.2X Refs %.2X [Decremented]\n",
477            Object, Object->Common.Type, NewCount));
478
479        /* Actually delete the object on a reference count of zero */
480
481        if (NewCount == 0)
482        {
483            AcpiUtDeleteInternalObj (Object);
484        }
485        break;
486
487    default:
488
489        AcpiOsReleaseLock (AcpiGbl_ReferenceCountLock, LockFlags);
490        ACPI_ERROR ((AE_INFO, "Unknown Reference Count action (0x%X)",
491            Action));
492        return;
493    }
494
495    /*
496     * Sanity check the reference count, for debug purposes only.
497     * (A deleted object will have a huge reference count)
498     */
499    if (NewCount > ACPI_MAX_REFERENCE_COUNT)
500    {
501        ACPI_WARNING ((AE_INFO,
502            "Large Reference Count (0x%X) in object %p, Type=0x%.2X",
503            NewCount, Object, Object->Common.Type));
504    }
505}
506
507
508/*******************************************************************************
509 *
510 * FUNCTION:    AcpiUtUpdateObjectReference
511 *
512 * PARAMETERS:  Object              - Increment ref count for this object
513 *                                    and all sub-objects
514 *              Action              - Either REF_INCREMENT or REF_DECREMENT
515 *
516 * RETURN:      Status
517 *
518 * DESCRIPTION: Increment the object reference count
519 *
520 * Object references are incremented when:
521 * 1) An object is attached to a Node (namespace object)
522 * 2) An object is copied (all subobjects must be incremented)
523 *
524 * Object references are decremented when:
525 * 1) An object is detached from an Node
526 *
527 ******************************************************************************/
528
529ACPI_STATUS
530AcpiUtUpdateObjectReference (
531    ACPI_OPERAND_OBJECT     *Object,
532    UINT16                  Action)
533{
534    ACPI_STATUS             Status = AE_OK;
535    ACPI_GENERIC_STATE      *StateList = NULL;
536    ACPI_OPERAND_OBJECT     *NextObject = NULL;
537    ACPI_OPERAND_OBJECT     *PrevObject;
538    ACPI_GENERIC_STATE      *State;
539    UINT32                  i;
540
541
542    ACPI_FUNCTION_NAME (UtUpdateObjectReference);
543
544
545    while (Object)
546    {
547        /* Make sure that this isn't a namespace handle */
548
549        if (ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_NAMED)
550        {
551            ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
552                "Object %p is NS handle\n", Object));
553            return (AE_OK);
554        }
555
556        /*
557         * All sub-objects must have their reference count incremented
558         * also. Different object types have different subobjects.
559         */
560        switch (Object->Common.Type)
561        {
562        case ACPI_TYPE_DEVICE:
563        case ACPI_TYPE_PROCESSOR:
564        case ACPI_TYPE_POWER:
565        case ACPI_TYPE_THERMAL:
566            /*
567             * Update the notify objects for these types (if present)
568             * Two lists, system and device notify handlers.
569             */
570            for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++)
571            {
572                PrevObject = Object->CommonNotify.NotifyList[i];
573                while (PrevObject)
574                {
575                    NextObject = PrevObject->Notify.Next[i];
576                    AcpiUtUpdateRefCount (PrevObject, Action);
577                    PrevObject = NextObject;
578                }
579            }
580            break;
581
582        case ACPI_TYPE_PACKAGE:
583            /*
584             * We must update all the sub-objects of the package,
585             * each of whom may have their own sub-objects.
586             */
587            for (i = 0; i < Object->Package.Count; i++)
588            {
589                /*
590                 * Null package elements are legal and can be simply
591                 * ignored.
592                 */
593                NextObject = Object->Package.Elements[i];
594                if (!NextObject)
595                {
596                    continue;
597                }
598
599                switch (NextObject->Common.Type)
600                {
601                case ACPI_TYPE_INTEGER:
602                case ACPI_TYPE_STRING:
603                case ACPI_TYPE_BUFFER:
604                    /*
605                     * For these very simple sub-objects, we can just
606                     * update the reference count here and continue.
607                     * Greatly increases performance of this operation.
608                     */
609                    AcpiUtUpdateRefCount (NextObject, Action);
610                    break;
611
612                default:
613                    /*
614                     * For complex sub-objects, push them onto the stack
615                     * for later processing (this eliminates recursion.)
616                     */
617                    Status = AcpiUtCreateUpdateStateAndPush (
618                        NextObject, Action, &StateList);
619                    if (ACPI_FAILURE (Status))
620                    {
621                        goto ErrorExit;
622                    }
623                    break;
624                }
625            }
626            NextObject = NULL;
627            break;
628
629        case ACPI_TYPE_BUFFER_FIELD:
630
631            NextObject = Object->BufferField.BufferObj;
632            break;
633
634        case ACPI_TYPE_LOCAL_REGION_FIELD:
635
636            NextObject = Object->Field.RegionObj;
637            break;
638
639        case ACPI_TYPE_LOCAL_BANK_FIELD:
640
641            NextObject = Object->BankField.BankObj;
642            Status = AcpiUtCreateUpdateStateAndPush (
643                Object->BankField.RegionObj, Action, &StateList);
644            if (ACPI_FAILURE (Status))
645            {
646                goto ErrorExit;
647            }
648            break;
649
650        case ACPI_TYPE_LOCAL_INDEX_FIELD:
651
652            NextObject = Object->IndexField.IndexObj;
653            Status = AcpiUtCreateUpdateStateAndPush (
654                Object->IndexField.DataObj, Action, &StateList);
655            if (ACPI_FAILURE (Status))
656            {
657                goto ErrorExit;
658            }
659            break;
660
661        case ACPI_TYPE_LOCAL_REFERENCE:
662            /*
663             * The target of an Index (a package, string, or buffer) or a named
664             * reference must track changes to the ref count of the index or
665             * target object.
666             */
667            if ((Object->Reference.Class == ACPI_REFCLASS_INDEX) ||
668                (Object->Reference.Class== ACPI_REFCLASS_NAME))
669            {
670                NextObject = Object->Reference.Object;
671            }
672            break;
673
674        case ACPI_TYPE_REGION:
675        default:
676
677            break; /* No subobjects for all other types */
678        }
679
680        /*
681         * Now we can update the count in the main object. This can only
682         * happen after we update the sub-objects in case this causes the
683         * main object to be deleted.
684         */
685        AcpiUtUpdateRefCount (Object, Action);
686        Object = NULL;
687
688        /* Move on to the next object to be updated */
689
690        if (NextObject)
691        {
692            Object = NextObject;
693            NextObject = NULL;
694        }
695        else if (StateList)
696        {
697            State = AcpiUtPopGenericState (&StateList);
698            Object = State->Update.Object;
699            AcpiUtDeleteGenericState (State);
700        }
701    }
702
703    return (AE_OK);
704
705
706ErrorExit:
707
708    ACPI_EXCEPTION ((AE_INFO, Status,
709        "Could not update object reference count"));
710
711    /* Free any stacked Update State objects */
712
713    while (StateList)
714    {
715        State = AcpiUtPopGenericState (&StateList);
716        AcpiUtDeleteGenericState (State);
717    }
718
719    return (Status);
720}
721
722
723/*******************************************************************************
724 *
725 * FUNCTION:    AcpiUtAddReference
726 *
727 * PARAMETERS:  Object          - Object whose reference count is to be
728 *                                incremented
729 *
730 * RETURN:      None
731 *
732 * DESCRIPTION: Add one reference to an ACPI object
733 *
734 ******************************************************************************/
735
736void
737AcpiUtAddReference (
738    ACPI_OPERAND_OBJECT     *Object)
739{
740
741    ACPI_FUNCTION_NAME (UtAddReference);
742
743
744    /* Ensure that we have a valid object */
745
746    if (!AcpiUtValidInternalObject (Object))
747    {
748        return;
749    }
750
751    ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
752        "Obj %p Current Refs=%X [To Be Incremented]\n",
753        Object, Object->Common.ReferenceCount));
754
755    /* Increment the reference count */
756
757    (void) AcpiUtUpdateObjectReference (Object, REF_INCREMENT);
758    return;
759}
760
761
762/*******************************************************************************
763 *
764 * FUNCTION:    AcpiUtRemoveReference
765 *
766 * PARAMETERS:  Object         - Object whose ref count will be decremented
767 *
768 * RETURN:      None
769 *
770 * DESCRIPTION: Decrement the reference count of an ACPI internal object
771 *
772 ******************************************************************************/
773
774void
775AcpiUtRemoveReference (
776    ACPI_OPERAND_OBJECT     *Object)
777{
778
779    ACPI_FUNCTION_NAME (UtRemoveReference);
780
781
782    /*
783     * Allow a NULL pointer to be passed in, just ignore it. This saves
784     * each caller from having to check. Also, ignore NS nodes.
785     */
786    if (!Object ||
787        (ACPI_GET_DESCRIPTOR_TYPE (Object) == ACPI_DESC_TYPE_NAMED))
788
789    {
790        return;
791    }
792
793    /* Ensure that we have a valid object */
794
795    if (!AcpiUtValidInternalObject (Object))
796    {
797        return;
798    }
799
800    ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
801        "Obj %p Current Refs=%X [To Be Decremented]\n",
802        Object, Object->Common.ReferenceCount));
803
804    /*
805     * Decrement the reference count, and only actually delete the object
806     * if the reference count becomes 0. (Must also decrement the ref count
807     * of all subobjects!)
808     */
809    (void) AcpiUtUpdateObjectReference (Object, REF_DECREMENT);
810    return;
811}
812