|
@@ -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);
|
|
|
}
|
|
|
}
|