summaryrefslogtreecommitdiff
path: root/drivers/acpi/acpica/utdelete.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/utdelete.c')
-rw-r--r--drivers/acpi/acpica/utdelete.c96
1 files changed, 49 insertions, 47 deletions
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index 2541de420249..29b930250b6f 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -359,19 +359,20 @@ void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list)
* FUNCTION: acpi_ut_update_ref_count
*
* PARAMETERS: object - Object whose ref count is to be updated
- * action - What to do
+ * action - What to do (REF_INCREMENT or REF_DECREMENT)
*
- * RETURN: New ref count
+ * RETURN: None. Sets new reference count within the object
*
- * DESCRIPTION: Modify the ref count and return it.
+ * DESCRIPTION: Modify the reference count for an internal acpi object
*
******************************************************************************/
static void
acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
{
- u16 count;
- u16 new_count;
+ u16 original_count;
+ u16 new_count = 0;
+ acpi_cpu_flags lock_flags;
ACPI_FUNCTION_NAME(ut_update_ref_count);
@@ -379,76 +380,79 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
return;
}
- count = object->common.reference_count;
- new_count = count;
-
/*
- * Perform the reference count action (increment, decrement, force delete)
+ * Always get the reference count lock. Note: Interpreter and/or
+ * Namespace is not always locked when this function is called.
*/
+ lock_flags = acpi_os_acquire_lock(acpi_gbl_reference_count_lock);
+ original_count = object->common.reference_count;
+
+ /* Perform the reference count action (increment, decrement) */
+
switch (action) {
case REF_INCREMENT:
- new_count++;
+ new_count = original_count + 1;
object->common.reference_count = new_count;
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
+
+ /* The current reference count should never be zero here */
+
+ if (!original_count) {
+ ACPI_WARNING((AE_INFO,
+ "Obj %p, Reference Count was zero before increment\n",
+ object));
+ }
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, [Incremented]\n",
- object, new_count));
+ "Obj %p Type %.2X Refs %.2X [Incremented]\n",
+ object, object->common.type, new_count));
break;
case REF_DECREMENT:
- if (count < 1) {
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
- object, new_count));
-
- new_count = 0;
- } else {
- new_count--;
+ /* The current reference count must be non-zero */
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, [Decremented]\n",
- object, new_count));
+ if (original_count) {
+ new_count = original_count - 1;
+ object->common.reference_count = new_count;
}
- if (object->common.type == ACPI_TYPE_METHOD) {
- ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Method Obj %p Refs=%X, [Decremented]\n",
- object, new_count));
- }
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
- object->common.reference_count = new_count;
- if (new_count == 0) {
- acpi_ut_delete_internal_obj(object);
+ if (!original_count) {
+ ACPI_WARNING((AE_INFO,
+ "Obj %p, Reference Count is already zero, cannot decrement\n",
+ object));
}
- break;
-
- case REF_FORCE_DELETE:
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "Obj %p Refs=%X, Force delete! (Set to 0)\n",
- object, count));
+ "Obj %p Type %.2X Refs %.2X [Decremented]\n",
+ object, object->common.type, new_count));
- new_count = 0;
- object->common.reference_count = new_count;
- acpi_ut_delete_internal_obj(object);
+ /* Actually delete the object on a reference count of zero */
+
+ if (new_count == 0) {
+ acpi_ut_delete_internal_obj(object);
+ }
break;
default:
- ACPI_ERROR((AE_INFO, "Unknown action (0x%X)", action));
- break;
+ acpi_os_release_lock(acpi_gbl_reference_count_lock, lock_flags);
+ ACPI_ERROR((AE_INFO, "Unknown Reference Count action (0x%X)",
+ action));
+ return;
}
/*
* Sanity check the reference count, for debug purposes only.
* (A deleted object will have a huge reference count)
*/
- if (count > ACPI_MAX_REFERENCE_COUNT) {
+ if (new_count > ACPI_MAX_REFERENCE_COUNT) {
ACPI_WARNING((AE_INFO,
- "Large Reference Count (0x%X) in object %p",
- count, object));
+ "Large Reference Count (0x%X) in object %p, Type=0x%.2X",
+ new_count, object, object->common.type));
}
}
@@ -458,8 +462,7 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action)
*
* PARAMETERS: object - Increment ref count for this object
* and all sub-objects
- * action - Either REF_INCREMENT or REF_DECREMENT or
- * REF_FORCE_DELETE
+ * action - Either REF_INCREMENT or REF_DECREMENT
*
* RETURN: Status
*
@@ -714,7 +717,6 @@ void acpi_ut_remove_reference(union acpi_operand_object *object)
/*
* Allow a NULL pointer to be passed in, just ignore it. This saves
* each caller from having to check. Also, ignore NS nodes.
- *
*/
if (!object ||
(ACPI_GET_DESCRIPTOR_TYPE(object) == ACPI_DESC_TYPE_NAMED)) {