ACPICA 20050708 from Bob Moore <robert.moore@intel.com>
[deliverable/linux.git] / drivers / acpi / dispatcher / dsmethod.c
CommitLineData
1da177e4
LT
1/******************************************************************************
2 *
3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2005, R. Byron Moore
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44
45#include <acpi/acpi.h>
46#include <acpi/acparser.h>
47#include <acpi/amlcode.h>
48#include <acpi/acdispat.h>
49#include <acpi/acinterp.h>
50#include <acpi/acnamesp.h>
51
52
53#define _COMPONENT ACPI_DISPATCHER
54 ACPI_MODULE_NAME ("dsmethod")
55
56
57/*******************************************************************************
58 *
59 * FUNCTION: acpi_ds_parse_method
60 *
61 * PARAMETERS: obj_handle - Method node
62 *
63 * RETURN: Status
64 *
65 * DESCRIPTION: Call the parser and parse the AML that is associated with the
66 * method.
67 *
68 * MUTEX: Assumes parser is locked
69 *
70 ******************************************************************************/
71
72acpi_status
73acpi_ds_parse_method (
74 acpi_handle obj_handle)
75{
76 acpi_status status;
77 union acpi_operand_object *obj_desc;
78 union acpi_parse_object *op;
79 struct acpi_namespace_node *node;
1da177e4
LT
80 struct acpi_walk_state *walk_state;
81
82
83 ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle);
84
85
86 /* Parameter Validation */
87
88 if (!obj_handle) {
89 return_ACPI_STATUS (AE_NULL_ENTRY);
90 }
91
92 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n",
93 acpi_ut_get_node_name (obj_handle), obj_handle));
94
95 /* Extract the method object from the method Node */
96
97 node = (struct acpi_namespace_node *) obj_handle;
98 obj_desc = acpi_ns_get_attached_object (node);
99 if (!obj_desc) {
100 return_ACPI_STATUS (AE_NULL_OBJECT);
101 }
102
103 /* Create a mutex for the method if there is a concurrency limit */
104
105 if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
106 (!obj_desc->method.semaphore)) {
107 status = acpi_os_create_semaphore (obj_desc->method.concurrency,
108 obj_desc->method.concurrency,
109 &obj_desc->method.semaphore);
110 if (ACPI_FAILURE (status)) {
111 return_ACPI_STATUS (status);
112 }
113 }
114
115 /*
116 * Allocate a new parser op to be the root of the parsed
117 * method tree
118 */
119 op = acpi_ps_alloc_op (AML_METHOD_OP);
120 if (!op) {
121 return_ACPI_STATUS (AE_NO_MEMORY);
122 }
123
124 /* Init new op with the method name and pointer back to the Node */
125
126 acpi_ps_set_name (op, node->name.integer);
127 op->common.node = node;
128
129 /*
130 * Get a new owner_id for objects created by this method. Namespace
131 * objects (such as Operation Regions) can be created during the
132 * first pass parse.
133 */
f9f4601f
RM
134 status = acpi_ut_allocate_owner_id (&obj_desc->method.owner_id);
135 if (ACPI_FAILURE (status)) {
136 goto cleanup;
137 }
1da177e4
LT
138
139 /* Create and initialize a new walk state */
140
f9f4601f
RM
141 walk_state = acpi_ds_create_walk_state (
142 obj_desc->method.owner_id, NULL, NULL, NULL);
1da177e4 143 if (!walk_state) {
88ac00f5 144 status = AE_NO_MEMORY;
f9f4601f 145 goto cleanup2;
1da177e4
LT
146 }
147
148 status = acpi_ds_init_aml_walk (walk_state, op, node,
149 obj_desc->method.aml_start,
150 obj_desc->method.aml_length, NULL, 1);
151 if (ACPI_FAILURE (status)) {
152 acpi_ds_delete_walk_state (walk_state);
f9f4601f 153 goto cleanup2;
1da177e4
LT
154 }
155
156 /*
157 * Parse the method, first pass
158 *
44f6c012
RM
159 * The first pass load is where newly declared named objects are added into
160 * the namespace. Actual evaluation of the named objects (what would be
161 * called a "second pass") happens during the actual execution of the
162 * method so that operands to the named objects can take on dynamic
163 * run-time values.
1da177e4
LT
164 */
165 status = acpi_ps_parse_aml (walk_state);
166 if (ACPI_FAILURE (status)) {
f9f4601f 167 goto cleanup2;
1da177e4
LT
168 }
169
170 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
171 "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
172 acpi_ut_get_node_name (obj_handle), obj_handle, op));
173
f9f4601f
RM
174cleanup2:
175 (void) acpi_ut_release_owner_id (obj_desc->method.owner_id);
176
88ac00f5 177cleanup:
1da177e4
LT
178 acpi_ps_delete_parse_tree (op);
179 return_ACPI_STATUS (status);
180}
181
182
183/*******************************************************************************
184 *
185 * FUNCTION: acpi_ds_begin_method_execution
186 *
187 * PARAMETERS: method_node - Node of the method
188 * obj_desc - The method object
189 * calling_method_node - Caller of this method (if non-null)
190 *
191 * RETURN: Status
192 *
193 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
194 * increments the thread count, and waits at the method semaphore
195 * for clearance to execute.
196 *
197 ******************************************************************************/
198
199acpi_status
200acpi_ds_begin_method_execution (
201 struct acpi_namespace_node *method_node,
202 union acpi_operand_object *obj_desc,
203 struct acpi_namespace_node *calling_method_node)
204{
205 acpi_status status = AE_OK;
206
207
208 ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node);
209
210
211 if (!method_node) {
212 return_ACPI_STATUS (AE_NULL_ENTRY);
213 }
214
215 /*
216 * If there is a concurrency limit on this method, we need to
217 * obtain a unit from the method semaphore.
218 */
219 if (obj_desc->method.semaphore) {
220 /*
221 * Allow recursive method calls, up to the reentrancy/concurrency
222 * limit imposed by the SERIALIZED rule and the sync_level method
223 * parameter.
224 *
225 * The point of this code is to avoid permanently blocking a
226 * thread that is making recursive method calls.
227 */
228 if (method_node == calling_method_node) {
229 if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
230 return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
231 }
232 }
233
234 /*
235 * Get a unit from the method semaphore. This releases the
236 * interpreter if we block
237 */
238 status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore,
239 ACPI_WAIT_FOREVER);
240 }
241
242 /*
243 * Increment the method parse tree thread count since it has been
244 * reentered one more time (even if it is the same thread)
245 */
246 obj_desc->method.thread_count++;
247 return_ACPI_STATUS (status);
248}
249
250
251/*******************************************************************************
252 *
253 * FUNCTION: acpi_ds_call_control_method
254 *
255 * PARAMETERS: Thread - Info for this thread
256 * this_walk_state - Current walk state
257 * Op - Current Op to be walked
258 *
259 * RETURN: Status
260 *
261 * DESCRIPTION: Transfer execution to a called control method
262 *
263 ******************************************************************************/
264
265acpi_status
266acpi_ds_call_control_method (
267 struct acpi_thread_state *thread,
268 struct acpi_walk_state *this_walk_state,
269 union acpi_parse_object *op)
270{
271 acpi_status status;
272 struct acpi_namespace_node *method_node;
f9f4601f 273 struct acpi_walk_state *next_walk_state = NULL;
1da177e4
LT
274 union acpi_operand_object *obj_desc;
275 struct acpi_parameter_info info;
276 u32 i;
277
278
279 ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state);
280
281 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
282 this_walk_state->prev_op, this_walk_state));
283
284 /*
285 * Get the namespace entry for the control method we are about to call
286 */
287 method_node = this_walk_state->method_call_node;
288 if (!method_node) {
289 return_ACPI_STATUS (AE_NULL_ENTRY);
290 }
291
292 obj_desc = acpi_ns_get_attached_object (method_node);
293 if (!obj_desc) {
294 return_ACPI_STATUS (AE_NULL_OBJECT);
295 }
296
f9f4601f
RM
297 status = acpi_ut_allocate_owner_id (&obj_desc->method.owner_id);
298 if (ACPI_FAILURE (status)) {
299 return_ACPI_STATUS (status);
300 }
1da177e4
LT
301
302 /* Init for new method, wait on concurrency semaphore */
303
304 status = acpi_ds_begin_method_execution (method_node, obj_desc,
305 this_walk_state->method_node);
306 if (ACPI_FAILURE (status)) {
f9f4601f 307 goto cleanup;
1da177e4
LT
308 }
309
310 if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
311 /* 1) Parse: Create a new walk state for the preempting walk */
312
f9f4601f 313 next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owner_id,
1da177e4
LT
314 op, obj_desc, NULL);
315 if (!next_walk_state) {
316 return_ACPI_STATUS (AE_NO_MEMORY);
317 }
318
319 /* Create and init a Root Node */
320
321 op = acpi_ps_create_scope_op ();
322 if (!op) {
323 status = AE_NO_MEMORY;
324 goto cleanup;
325 }
326
327 status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
328 obj_desc->method.aml_start, obj_desc->method.aml_length,
329 NULL, 1);
330 if (ACPI_FAILURE (status)) {
331 acpi_ds_delete_walk_state (next_walk_state);
332 goto cleanup;
333 }
334
335 /* Begin AML parse */
336
337 status = acpi_ps_parse_aml (next_walk_state);
338 acpi_ps_delete_parse_tree (op);
339 }
340
341 /* 2) Execute: Create a new state for the preempting walk */
342
f9f4601f 343 next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owner_id,
1da177e4
LT
344 NULL, obj_desc, thread);
345 if (!next_walk_state) {
346 status = AE_NO_MEMORY;
347 goto cleanup;
348 }
349 /*
350 * The resolved arguments were put on the previous walk state's operand
351 * stack. Operands on the previous walk state stack always
352 * start at index 0.
353 * Null terminate the list of arguments
354 */
355 this_walk_state->operands [this_walk_state->num_operands] = NULL;
356
357 info.parameters = &this_walk_state->operands[0];
358 info.parameter_type = ACPI_PARAM_ARGS;
359
360 status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node,
361 obj_desc->method.aml_start, obj_desc->method.aml_length,
362 &info, 3);
363 if (ACPI_FAILURE (status)) {
364 goto cleanup;
365 }
366
367 /*
368 * Delete the operands on the previous walkstate operand stack
369 * (they were copied to new objects)
370 */
371 for (i = 0; i < obj_desc->method.param_count; i++) {
372 acpi_ut_remove_reference (this_walk_state->operands [i]);
373 this_walk_state->operands [i] = NULL;
374 }
375
376 /* Clear the operand stack */
377
378 this_walk_state->num_operands = 0;
379
380 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
381 "Starting nested execution, newstate=%p\n", next_walk_state));
382
383 if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
384 status = obj_desc->method.implementation (next_walk_state);
385 return_ACPI_STATUS (status);
386 }
387
388 return_ACPI_STATUS (AE_OK);
389
390
391 /* On error, we must delete the new walk state */
392
393cleanup:
f9f4601f 394 (void) acpi_ut_release_owner_id (obj_desc->method.owner_id);
1da177e4
LT
395 if (next_walk_state && (next_walk_state->method_desc)) {
396 /* Decrement the thread count on the method parse tree */
397
398 next_walk_state->method_desc->method.thread_count--;
399 }
400 (void) acpi_ds_terminate_control_method (next_walk_state);
401 acpi_ds_delete_walk_state (next_walk_state);
402 return_ACPI_STATUS (status);
403}
404
405
406/*******************************************************************************
407 *
408 * FUNCTION: acpi_ds_restart_control_method
409 *
410 * PARAMETERS: walk_state - State for preempted method (caller)
411 * return_desc - Return value from the called method
412 *
413 * RETURN: Status
414 *
415 * DESCRIPTION: Restart a method that was preempted by another (nested) method
416 * invocation. Handle the return value (if any) from the callee.
417 *
418 ******************************************************************************/
419
420acpi_status
421acpi_ds_restart_control_method (
422 struct acpi_walk_state *walk_state,
423 union acpi_operand_object *return_desc)
424{
425 acpi_status status;
426
427
428 ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state);
429
430
431 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
432 "****Restart [%4.4s] Op %p return_value_from_callee %p\n",
433 (char *) &walk_state->method_node->name, walk_state->method_call_op,
434 return_desc));
435
436 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
437 " return_from_this_method_used?=%X res_stack %p Walk %p\n",
438 walk_state->return_used,
439 walk_state->results, walk_state));
440
441 /* Did the called method return a value? */
442
443 if (return_desc) {
444 /* Are we actually going to use the return value? */
445
446 if (walk_state->return_used) {
447 /* Save the return value from the previous method */
448
449 status = acpi_ds_result_push (return_desc, walk_state);
450 if (ACPI_FAILURE (status)) {
451 acpi_ut_remove_reference (return_desc);
452 return_ACPI_STATUS (status);
453 }
454
455 /*
456 * Save as THIS method's return value in case it is returned
457 * immediately to yet another method
458 */
459 walk_state->return_desc = return_desc;
460 }
461
462 /*
463 * The following code is the
464 * optional support for a so-called "implicit return". Some AML code
465 * assumes that the last value of the method is "implicitly" returned
466 * to the caller. Just save the last result as the return value.
467 * NOTE: this is optional because the ASL language does not actually
468 * support this behavior.
469 */
470 else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) {
471 /*
472 * Delete the return value if it will not be used by the
473 * calling method
474 */
475 acpi_ut_remove_reference (return_desc);
476 }
477 }
478
479 return_ACPI_STATUS (AE_OK);
480}
481
482
483/*******************************************************************************
484 *
485 * FUNCTION: acpi_ds_terminate_control_method
486 *
487 * PARAMETERS: walk_state - State of the method
488 *
489 * RETURN: Status
490 *
491 * DESCRIPTION: Terminate a control method. Delete everything that the method
492 * created, delete all locals and arguments, and delete the parse
493 * tree if requested.
494 *
495 ******************************************************************************/
496
497acpi_status
498acpi_ds_terminate_control_method (
499 struct acpi_walk_state *walk_state)
500{
501 union acpi_operand_object *obj_desc;
502 struct acpi_namespace_node *method_node;
503 acpi_status status;
504
505
506 ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state);
507
508
509 if (!walk_state) {
510 return (AE_BAD_PARAMETER);
511 }
512
513 /* The current method object was saved in the walk state */
514
515 obj_desc = walk_state->method_desc;
516 if (!obj_desc) {
517 return_ACPI_STATUS (AE_OK);
518 }
519
520 /* Delete all arguments and locals */
521
522 acpi_ds_method_data_delete_all (walk_state);
523
524 /*
525 * Lock the parser while we terminate this method.
526 * If this is the last thread executing the method,
527 * we have additional cleanup to perform
528 */
529 status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER);
530 if (ACPI_FAILURE (status)) {
531 return_ACPI_STATUS (status);
532 }
533
534 /* Signal completion of the execution of this method if necessary */
535
536 if (walk_state->method_desc->method.semaphore) {
537 status = acpi_os_signal_semaphore (
538 walk_state->method_desc->method.semaphore, 1);
539 if (ACPI_FAILURE (status)) {
540 ACPI_REPORT_ERROR (("Could not signal method semaphore\n"));
541 status = AE_OK;
542
543 /* Ignore error and continue cleanup */
544 }
545 }
546
547 if (walk_state->method_desc->method.thread_count) {
548 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
549 "*** Not deleting method namespace, there are still %d threads\n",
550 walk_state->method_desc->method.thread_count));
551 }
552
553 if (!walk_state->method_desc->method.thread_count) {
554 /*
555 * Support to dynamically change a method from not_serialized to
556 * Serialized if it appears that the method is written foolishly and
557 * does not support multiple thread execution. The best example of this
558 * is if such a method creates namespace objects and blocks. A second
559 * thread will fail with an AE_ALREADY_EXISTS exception
560 *
561 * This code is here because we must wait until the last thread exits
562 * before creating the synchronization semaphore.
563 */
564 if ((walk_state->method_desc->method.concurrency == 1) &&
565 (!walk_state->method_desc->method.semaphore)) {
566 status = acpi_os_create_semaphore (1,
567 1,
568 &walk_state->method_desc->method.semaphore);
569 }
570
571 /*
572 * There are no more threads executing this method. Perform
573 * additional cleanup.
574 *
575 * The method Node is stored in the walk state
576 */
577 method_node = walk_state->method_node;
578
579 /*
580 * Delete any namespace entries created immediately underneath
581 * the method
582 */
583 status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
584 if (ACPI_FAILURE (status)) {
585 return_ACPI_STATUS (status);
586 }
587
588 if (method_node->child) {
589 acpi_ns_delete_namespace_subtree (method_node);
590 }
591
592 /*
593 * Delete any namespace entries created anywhere else within
594 * the namespace
595 */
f9f4601f 596 acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owner_id);
1da177e4
LT
597 status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
598 if (ACPI_FAILURE (status)) {
599 return_ACPI_STATUS (status);
600 }
601 }
602
603 status = acpi_ut_release_mutex (ACPI_MTX_PARSER);
604 return_ACPI_STATUS (status);
605}
606
607
This page took 0.061762 seconds and 5 git commands to generate.