From: Robert Moore <robert.mo...@intel.com>

It is reported that the auto-serialization mechanism has broken some
machine.  This patch fixes the issues by igoring the SyncLevel
attribute of the marked Method.

References: http://www.spinics.net/lists/linux-acpi/msg49496.html
Reported-by: Valdis Kletnieks <validis.kletni...@vt.edu>
Reported-by: Sabrina Dubroka <s...@queasysnail.net>
Signed-off-by: Bob Moore <robert.mo...@intel.com>
Signed-off-by: Lv Zheng <lv.zh...@intel.com>
---
 drivers/acpi/acpica/acobject.h |    3 ++-
 drivers/acpi/acpica/dsmethod.c |   24 +++++++++++++++++++-----
 2 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 1a4d618..22fb644 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -193,7 +193,8 @@ struct acpi_object_method {
 #define ACPI_METHOD_INTERNAL_ONLY       0x02   /* Method is implemented 
internally (_OSI) */
 #define ACPI_METHOD_SERIALIZED          0x04   /* Method is serialized */
 #define ACPI_METHOD_SERIALIZED_PENDING  0x08   /* Method is to be marked 
serialized */
-#define ACPI_METHOD_MODIFIED_NAMESPACE  0x10   /* Method modified the 
namespace */
+#define ACPI_METHOD_IGNORE_SYNC_LEVEL   0x10   /* Method was auto-serialized 
at table load time */
+#define ACPI_METHOD_MODIFIED_NAMESPACE  0x20   /* Method modified the 
namespace */
 
 /******************************************************************************
  *
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 73764c7..3c7f737 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -175,8 +175,15 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state 
*walk_state,
         * At this point, we know we have a Named object opcode.
         * Mark the method as serialized. Later code will create a mutex for
         * this method to enforce serialization.
+        *
+        * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore 
the
+        * Sync Level mechanism for this method, even though it is now 
serialized.
+        * Otherwise, there can be conflicts with existing ASL code that 
actually
+        * uses sync levels.
         */
-       walk_state->method_desc->method.info_flags |= ACPI_METHOD_SERIALIZED;
+       walk_state->method_desc->method.sync_level = 0;
+       walk_state->method_desc->method.info_flags |=
+           (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
@@ -349,13 +356,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node 
*method_node,
                /*
                 * The current_sync_level (per-thread) must be less than or 
equal to
                 * the sync level of the method. This mechanism provides some
-                * deadlock prevention
+                * deadlock prevention.
+                *
+                * If the method was auto-serialized, we just ignore the sync 
level
+                * mechanism, because auto-serialization of methods can 
interfere
+                * with ASL code that actually uses sync levels.
                 *
                 * Top-level method invocation has no walk state at this point
                 */
                if (walk_state &&
-                   (walk_state->thread->current_sync_level >
-                    obj_desc->method.mutex->mutex.sync_level)) {
+                   (!(obj_desc->method.
+                      info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
+                   && (walk_state->thread->current_sync_level >
+                       obj_desc->method.mutex->mutex.sync_level)) {
                        ACPI_ERROR((AE_INFO,
                                    "Cannot acquire Mutex for method [%4.4s], 
current SyncLevel is too large (%u)",
                                    acpi_ut_get_node_name(method_node),
@@ -800,7 +813,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object 
*method_desc,
                        method_desc->method.info_flags &=
                            ~ACPI_METHOD_SERIALIZED_PENDING;
                        method_desc->method.info_flags |=
-                           ACPI_METHOD_SERIALIZED;
+                           (ACPI_METHOD_SERIALIZED |
+                            ACPI_METHOD_IGNORE_SYNC_LEVEL);
                        method_desc->method.sync_level = 0;
                }
 
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to