diff options
Diffstat (limited to 'drivers/acpi/acpica/dsmethod.c')
| -rw-r--r-- | drivers/acpi/acpica/dsmethod.c | 64 | 
1 files changed, 48 insertions, 16 deletions
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index d94dd8974b5..5d797751e20 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@   *****************************************************************************/  /* - * Copyright (C) 2000 - 2010, Intel Corp. + * Copyright (C) 2000 - 2011, Intel Corp.   * All rights reserved.   *   * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,6 @@  #include <acpi/acpi.h>  #include "accommon.h" -#include "amlcode.h"  #include "acdispat.h"  #include "acinterp.h"  #include "acnamesp.h" @@ -201,7 +200,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,  	/*  	 * If this method is serialized, we need to acquire the method mutex.  	 */ -	if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) { +	if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {  		/*  		 * Create a mutex for the method if it is defined to be Serialized  		 * and a mutex has not already been created. We defer the mutex creation @@ -413,8 +412,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,  	/* Invoke an internal method if necessary */ -	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { -		status = obj_desc->method.extra.implementation(next_walk_state); +	if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { +		status = +		    obj_desc->method.dispatch.implementation(next_walk_state);  		if (status == AE_OK) {  			status = AE_CTRL_TERMINATE;  		} @@ -579,11 +579,14 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,  		/*  		 * Delete any namespace objects created anywhere within the -		 * namespace by the execution of this method. Unless this method -		 * is a module-level executable code method, in which case we -		 * want make the objects permanent. +		 * namespace by the execution of this method. Unless: +		 * 1) This method is a module-level executable code method, in which +		 *    case we want make the objects permanent. +		 * 2) There are other threads executing the method, in which case we +		 *    will wait until the last thread has completed.  		 */ -		if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { +		if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) +		    && (method_desc->method.thread_count == 1)) {  			/* Delete any direct children of (created by) this method */ @@ -593,12 +596,17 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,  			/*  			 * Delete any objects that were created by this method  			 * elsewhere in the namespace (if any were created). +			 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the +			 * deletion such that we don't have to perform an entire +			 * namespace walk for every control method execution.  			 */  			if (method_desc->method. -			    flags & AOPOBJ_MODIFIED_NAMESPACE) { +			    info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {  				acpi_ns_delete_namespace_by_owner(method_desc->  								  method.  								  owner_id); +				method_desc->method.info_flags &= +				    ~ACPI_METHOD_MODIFIED_NAMESPACE;  			}  		}  	} @@ -629,19 +637,43 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,  		 * Serialized if it appears that the method is incorrectly written and  		 * does not support multiple thread execution. The best example of this  		 * is if such a method creates namespace objects and blocks. A second -		 * thread will fail with an AE_ALREADY_EXISTS exception +		 * thread will fail with an AE_ALREADY_EXISTS exception.  		 *  		 * This code is here because we must wait until the last thread exits -		 * before creating the synchronization semaphore. +		 * before marking the method as serialized.  		 */ -		if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED) -		    && (!method_desc->method.mutex)) { -			(void)acpi_ds_create_method_mutex(method_desc); +		if (method_desc->method. +		    info_flags & ACPI_METHOD_SERIALIZED_PENDING) { +			if (walk_state) { +				ACPI_INFO((AE_INFO, +					   "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", +					   walk_state->method_node->name. +					   ascii)); +			} + +			/* +			 * Method tried to create an object twice and was marked as +			 * "pending serialized". The probable cause is that the method +			 * cannot handle reentrancy. +			 * +			 * The method was created as not_serialized, but it tried to create +			 * a named object and then blocked, causing the second thread +			 * entrance to begin and then fail. Workaround this problem by +			 * marking the method permanently as Serialized when the last +			 * thread exits here. +			 */ +			method_desc->method.info_flags &= +			    ~ACPI_METHOD_SERIALIZED_PENDING; +			method_desc->method.info_flags |= +			    ACPI_METHOD_SERIALIZED; +			method_desc->method.sync_level = 0;  		}  		/* No more threads, we can free the owner_id */ -		if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) { +		if (! +		    (method_desc->method. +		     info_flags & ACPI_METHOD_MODULE_LEVEL)) {  			acpi_ut_release_owner_id(&method_desc->method.owner_id);  		}  	}  |