diff options
Diffstat (limited to 'drivers/acpi/acpica/dsmethod.c')
-rw-r--r-- | drivers/acpi/acpica/dsmethod.c | 156 |
1 files changed, 151 insertions, 5 deletions
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 2c6d42c2bc01..3c7f7378b94d 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c | |||
@@ -49,16 +49,155 @@ | |||
49 | #ifdef ACPI_DISASSEMBLER | 49 | #ifdef ACPI_DISASSEMBLER |
50 | #include "acdisasm.h" | 50 | #include "acdisasm.h" |
51 | #endif | 51 | #endif |
52 | #include "acparser.h" | ||
53 | #include "amlcode.h" | ||
52 | 54 | ||
53 | #define _COMPONENT ACPI_DISPATCHER | 55 | #define _COMPONENT ACPI_DISPATCHER |
54 | ACPI_MODULE_NAME("dsmethod") | 56 | ACPI_MODULE_NAME("dsmethod") |
55 | 57 | ||
56 | /* Local prototypes */ | 58 | /* Local prototypes */ |
57 | static acpi_status | 59 | static acpi_status |
60 | acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, | ||
61 | union acpi_parse_object **out_op); | ||
62 | |||
63 | static acpi_status | ||
58 | acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); | 64 | acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); |
59 | 65 | ||
60 | /******************************************************************************* | 66 | /******************************************************************************* |
61 | * | 67 | * |
68 | * FUNCTION: acpi_ds_auto_serialize_method | ||
69 | * | ||
70 | * PARAMETERS: node - Namespace Node of the method | ||
71 | * obj_desc - Method object attached to node | ||
72 | * | ||
73 | * RETURN: Status | ||
74 | * | ||
75 | * DESCRIPTION: Parse a control method AML to scan for control methods that | ||
76 | * need serialization due to the creation of named objects. | ||
77 | * | ||
78 | * NOTE: It is a bit of overkill to mark all such methods serialized, since | ||
79 | * there is only a problem if the method actually blocks during execution. | ||
80 | * A blocking operation is, for example, a Sleep() operation, or any access | ||
81 | * to an operation region. However, it is probably not possible to easily | ||
82 | * detect whether a method will block or not, so we simply mark all suspicious | ||
83 | * methods as serialized. | ||
84 | * | ||
85 | * NOTE2: This code is essentially a generic routine for parsing a single | ||
86 | * control method. | ||
87 | * | ||
88 | ******************************************************************************/ | ||
89 | |||
90 | acpi_status | ||
91 | acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, | ||
92 | union acpi_operand_object *obj_desc) | ||
93 | { | ||
94 | acpi_status status; | ||
95 | union acpi_parse_object *op = NULL; | ||
96 | struct acpi_walk_state *walk_state; | ||
97 | |||
98 | ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node); | ||
99 | |||
100 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
101 | "Method auto-serialization parse [%4.4s] %p\n", | ||
102 | acpi_ut_get_node_name(node), node)); | ||
103 | |||
104 | /* Create/Init a root op for the method parse tree */ | ||
105 | |||
106 | op = acpi_ps_alloc_op(AML_METHOD_OP); | ||
107 | if (!op) { | ||
108 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
109 | } | ||
110 | |||
111 | acpi_ps_set_name(op, node->name.integer); | ||
112 | op->common.node = node; | ||
113 | |||
114 | /* Create and initialize a new walk state */ | ||
115 | |||
116 | walk_state = | ||
117 | acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL); | ||
118 | if (!walk_state) { | ||
119 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
120 | } | ||
121 | |||
122 | status = | ||
123 | acpi_ds_init_aml_walk(walk_state, op, node, | ||
124 | obj_desc->method.aml_start, | ||
125 | obj_desc->method.aml_length, NULL, 0); | ||
126 | if (ACPI_FAILURE(status)) { | ||
127 | acpi_ds_delete_walk_state(walk_state); | ||
128 | return_ACPI_STATUS(status); | ||
129 | } | ||
130 | |||
131 | walk_state->descending_callback = acpi_ds_detect_named_opcodes; | ||
132 | |||
133 | /* Parse the method, scan for creation of named objects */ | ||
134 | |||
135 | status = acpi_ps_parse_aml(walk_state); | ||
136 | if (ACPI_FAILURE(status)) { | ||
137 | return_ACPI_STATUS(status); | ||
138 | } | ||
139 | |||
140 | acpi_ps_delete_parse_tree(op); | ||
141 | return_ACPI_STATUS(status); | ||
142 | } | ||
143 | |||
144 | /******************************************************************************* | ||
145 | * | ||
146 | * FUNCTION: acpi_ds_detect_named_opcodes | ||
147 | * | ||
148 | * PARAMETERS: walk_state - Current state of the parse tree walk | ||
149 | * out_op - Unused, required for parser interface | ||
150 | * | ||
151 | * RETURN: Status | ||
152 | * | ||
153 | * DESCRIPTION: Descending callback used during the loading of ACPI tables. | ||
154 | * Currently used to detect methods that must be marked serialized | ||
155 | * in order to avoid problems with the creation of named objects. | ||
156 | * | ||
157 | ******************************************************************************/ | ||
158 | |||
159 | static acpi_status | ||
160 | acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, | ||
161 | union acpi_parse_object **out_op) | ||
162 | { | ||
163 | |||
164 | ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes); | ||
165 | |||
166 | /* We are only interested in opcodes that create a new name */ | ||
167 | |||
168 | if (! | ||
169 | (walk_state->op_info-> | ||
170 | flags & (AML_NAMED | AML_CREATE | AML_FIELD))) { | ||
171 | return (AE_OK); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * At this point, we know we have a Named object opcode. | ||
176 | * Mark the method as serialized. Later code will create a mutex for | ||
177 | * this method to enforce serialization. | ||
178 | * | ||
179 | * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the | ||
180 | * Sync Level mechanism for this method, even though it is now serialized. | ||
181 | * Otherwise, there can be conflicts with existing ASL code that actually | ||
182 | * uses sync levels. | ||
183 | */ | ||
184 | walk_state->method_desc->method.sync_level = 0; | ||
185 | walk_state->method_desc->method.info_flags |= | ||
186 | (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); | ||
187 | |||
188 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
189 | "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", | ||
190 | walk_state->method_node->name.ascii, | ||
191 | walk_state->method_node, walk_state->op_info->name, | ||
192 | walk_state->opcode)); | ||
193 | |||
194 | /* Abort the parse, no need to examine this method any further */ | ||
195 | |||
196 | return (AE_CTRL_TERMINATE); | ||
197 | } | ||
198 | |||
199 | /******************************************************************************* | ||
200 | * | ||
62 | * FUNCTION: acpi_ds_method_error | 201 | * FUNCTION: acpi_ds_method_error |
63 | * | 202 | * |
64 | * PARAMETERS: status - Execution status | 203 | * PARAMETERS: status - Execution status |
@@ -74,7 +213,7 @@ acpi_ds_create_method_mutex(union acpi_operand_object *method_desc); | |||
74 | ******************************************************************************/ | 213 | ******************************************************************************/ |
75 | 214 | ||
76 | acpi_status | 215 | acpi_status |
77 | acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state) | 216 | acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) |
78 | { | 217 | { |
79 | ACPI_FUNCTION_ENTRY(); | 218 | ACPI_FUNCTION_ENTRY(); |
80 | 219 | ||
@@ -217,13 +356,19 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, | |||
217 | /* | 356 | /* |
218 | * The current_sync_level (per-thread) must be less than or equal to | 357 | * The current_sync_level (per-thread) must be less than or equal to |
219 | * the sync level of the method. This mechanism provides some | 358 | * the sync level of the method. This mechanism provides some |
220 | * deadlock prevention | 359 | * deadlock prevention. |
360 | * | ||
361 | * If the method was auto-serialized, we just ignore the sync level | ||
362 | * mechanism, because auto-serialization of methods can interfere | ||
363 | * with ASL code that actually uses sync levels. | ||
221 | * | 364 | * |
222 | * Top-level method invocation has no walk state at this point | 365 | * Top-level method invocation has no walk state at this point |
223 | */ | 366 | */ |
224 | if (walk_state && | 367 | if (walk_state && |
225 | (walk_state->thread->current_sync_level > | 368 | (!(obj_desc->method. |
226 | obj_desc->method.mutex->mutex.sync_level)) { | 369 | info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) |
370 | && (walk_state->thread->current_sync_level > | ||
371 | obj_desc->method.mutex->mutex.sync_level)) { | ||
227 | ACPI_ERROR((AE_INFO, | 372 | ACPI_ERROR((AE_INFO, |
228 | "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", | 373 | "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", |
229 | acpi_ut_get_node_name(method_node), | 374 | acpi_ut_get_node_name(method_node), |
@@ -668,7 +813,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, | |||
668 | method_desc->method.info_flags &= | 813 | method_desc->method.info_flags &= |
669 | ~ACPI_METHOD_SERIALIZED_PENDING; | 814 | ~ACPI_METHOD_SERIALIZED_PENDING; |
670 | method_desc->method.info_flags |= | 815 | method_desc->method.info_flags |= |
671 | ACPI_METHOD_SERIALIZED; | 816 | (ACPI_METHOD_SERIALIZED | |
817 | ACPI_METHOD_IGNORE_SYNC_LEVEL); | ||
672 | method_desc->method.sync_level = 0; | 818 | method_desc->method.sync_level = 0; |
673 | } | 819 | } |
674 | 820 | ||