File: /usr/src/linux/drivers/acpi/dispatcher/dsmethod.c
1 /******************************************************************************
2 *
3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
4 * $Revision: 65 $
5 *
6 *****************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include "acpi.h"
28 #include "acparser.h"
29 #include "amlcode.h"
30 #include "acdispat.h"
31 #include "acinterp.h"
32 #include "acnamesp.h"
33 #include "actables.h"
34 #include "acdebug.h"
35
36
37 #define _COMPONENT ACPI_DISPATCHER
38 MODULE_NAME ("dsmethod")
39
40
41 /*******************************************************************************
42 *
43 * FUNCTION: Acpi_ds_parse_method
44 *
45 * PARAMETERS: Obj_handle - Node of the method
46 * Level - Current nesting level
47 * Context - Points to a method counter
48 * Return_value - Not used
49 *
50 * RETURN: Status
51 *
52 * DESCRIPTION: Call the parser and parse the AML that is
53 * associated with the method.
54 *
55 * MUTEX: Assumes parser is locked
56 *
57 ******************************************************************************/
58
59 acpi_status
60 acpi_ds_parse_method (
61 acpi_handle obj_handle)
62 {
63 acpi_status status;
64 acpi_operand_object *obj_desc;
65 acpi_parse_object *op;
66 acpi_namespace_node *node;
67 acpi_owner_id owner_id;
68
69
70 FUNCTION_TRACE_PTR ("Ds_parse_method", obj_handle);
71
72
73 /* Parameter Validation */
74
75 if (!obj_handle) {
76 return_ACPI_STATUS (AE_NULL_ENTRY);
77 }
78
79 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Parsing [%4.4s] **** Named_obj=%p\n",
80 &((acpi_namespace_node *)obj_handle)->name, obj_handle));
81
82
83 /* Extract the method object from the method Node */
84
85 node = (acpi_namespace_node *) obj_handle;
86 obj_desc = node->object;
87 if (!obj_desc) {
88 return_ACPI_STATUS (AE_NULL_OBJECT);
89 }
90
91 /* Create a mutex for the method if there is a concurrency limit */
92
93 if ((obj_desc->method.concurrency != INFINITE_CONCURRENCY) &&
94 (!obj_desc->method.semaphore)) {
95 status = acpi_os_create_semaphore (obj_desc->method.concurrency,
96 obj_desc->method.concurrency,
97 &obj_desc->method.semaphore);
98 if (ACPI_FAILURE (status)) {
99 return_ACPI_STATUS (status);
100 }
101 }
102
103 /*
104 * Allocate a new parser op to be the root of the parsed
105 * method tree
106 */
107 op = acpi_ps_alloc_op (AML_METHOD_OP);
108 if (!op) {
109 return_ACPI_STATUS (AE_NO_MEMORY);
110 }
111
112 /* Init new op with the method name and pointer back to the Node */
113
114 acpi_ps_set_name (op, node->name);
115 op->node = node;
116
117
118 /*
119 * Parse the method, first pass
120 *
121 * The first pass load is where newly declared named objects are
122 * added into the namespace. Actual evaluation of
123 * the named objects (what would be called a "second
124 * pass") happens during the actual execution of the
125 * method so that operands to the named objects can
126 * take on dynamic run-time values.
127 */
128 status = acpi_ps_parse_aml (op, obj_desc->method.pcode,
129 obj_desc->method.pcode_length,
130 ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE,
131 node, NULL, NULL,
132 acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
133
134 if (ACPI_FAILURE (status)) {
135 return_ACPI_STATUS (status);
136 }
137
138 /* Get a new Owner_id for objects created by this method */
139
140 owner_id = acpi_ut_allocate_owner_id (OWNER_TYPE_METHOD);
141 obj_desc->method.owning_id = owner_id;
142
143 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** [%4.4s] Parsed **** Named_obj=%p Op=%p\n",
144 &((acpi_namespace_node *)obj_handle)->name, obj_handle, op));
145
146 /* Install the parsed tree in the method object */
147 /* TBD: [Restructure] Obsolete field? */
148
149 acpi_ps_delete_parse_tree (op);
150
151 return_ACPI_STATUS (status);
152 }
153
154
155 /*******************************************************************************
156 *
157 * FUNCTION: Acpi_ds_begin_method_execution
158 *
159 * PARAMETERS: Method_node - Node of the method
160 * Obj_desc - The method object
161 * Calling_method_node - Caller of this method (if non-null)
162 *
163 * RETURN: Status
164 *
165 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
166 * increments the thread count, and waits at the method semaphore
167 * for clearance to execute.
168 *
169 * MUTEX: Locks/unlocks parser.
170 *
171 ******************************************************************************/
172
173 acpi_status
174 acpi_ds_begin_method_execution (
175 acpi_namespace_node *method_node,
176 acpi_operand_object *obj_desc,
177 acpi_namespace_node *calling_method_node)
178 {
179 acpi_status status = AE_OK;
180
181
182 FUNCTION_TRACE_PTR ("Ds_begin_method_execution", method_node);
183
184
185 if (!method_node) {
186 return_ACPI_STATUS (AE_NULL_ENTRY);
187 }
188
189
190 /*
191 * If there is a concurrency limit on this method, we need to
192 * obtain a unit from the method semaphore.
193 */
194 if (obj_desc->method.semaphore) {
195 /*
196 * Allow recursive method calls, up to the reentrancy/concurrency
197 * limit imposed by the SERIALIZED rule and the Sync_level method
198 * parameter.
199 *
200 * The point of this code is to avoid permanently blocking a
201 * thread that is making recursive method calls.
202 */
203 if (method_node == calling_method_node) {
204 if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
205 return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
206 }
207 }
208
209 /*
210 * Get a unit from the method semaphore. This releases the
211 * interpreter if we block
212 */
213 status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore,
214 WAIT_FOREVER);
215 }
216
217
218 /*
219 * Increment the method parse tree thread count since it has been
220 * reentered one more time (even if it is the same thread)
221 */
222 obj_desc->method.thread_count++;
223
224 return_ACPI_STATUS (status);
225 }
226
227
228 /*******************************************************************************
229 *
230 * FUNCTION: Acpi_ds_call_control_method
231 *
232 * PARAMETERS: Walk_state - Current state of the walk
233 * Op - Current Op to be walked
234 *
235 * RETURN: Status
236 *
237 * DESCRIPTION: Transfer execution to a called control method
238 *
239 ******************************************************************************/
240
241 acpi_status
242 acpi_ds_call_control_method (
243 acpi_walk_list *walk_list,
244 acpi_walk_state *this_walk_state,
245 acpi_parse_object *op)
246 {
247 acpi_status status;
248 acpi_namespace_node *method_node;
249 acpi_operand_object *obj_desc;
250 acpi_walk_state *next_walk_state;
251 acpi_parse_state *parser_state;
252 u32 i;
253
254
255 FUNCTION_TRACE_PTR ("Ds_call_control_method", this_walk_state);
256
257 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
258 this_walk_state->prev_op, this_walk_state));
259
260 /*
261 * Get the namespace entry for the control method we are about to call
262 */
263 method_node = this_walk_state->method_call_node;
264 if (!method_node) {
265 return_ACPI_STATUS (AE_NULL_ENTRY);
266 }
267
268 obj_desc = acpi_ns_get_attached_object (method_node);
269 if (!obj_desc) {
270 return_ACPI_STATUS (AE_NULL_OBJECT);
271 }
272
273
274 /* Init for new method, wait on concurrency semaphore */
275
276 status = acpi_ds_begin_method_execution (method_node, obj_desc,
277 this_walk_state->method_node);
278 if (ACPI_FAILURE (status)) {
279 return_ACPI_STATUS (status);
280 }
281
282 /* Create and initialize a new parser state */
283
284 parser_state = acpi_ps_create_state (obj_desc->method.pcode,
285 obj_desc->method.pcode_length);
286 if (!parser_state) {
287 return_ACPI_STATUS (AE_NO_MEMORY);
288 }
289
290 acpi_ps_init_scope (parser_state, NULL);
291 parser_state->start_node = method_node;
292
293
294 /* Create a new state for the preempting walk */
295
296 next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
297 NULL, obj_desc, walk_list);
298 if (!next_walk_state) {
299 /* TBD: delete parser state */
300
301 return_ACPI_STATUS (AE_NO_MEMORY);
302 }
303
304 next_walk_state->walk_type = WALK_METHOD;
305 next_walk_state->method_node = method_node;
306 next_walk_state->parser_state = parser_state;
307 next_walk_state->parse_flags = this_walk_state->parse_flags;
308 next_walk_state->descending_callback = this_walk_state->descending_callback;
309 next_walk_state->ascending_callback = this_walk_state->ascending_callback;
310
311 /* The Next_op of the Next_walk will be the beginning of the method */
312 /* TBD: [Restructure] -- obsolete? */
313
314 next_walk_state->next_op = NULL;
315
316 /* Open a new scope */
317
318 status = acpi_ds_scope_stack_push (method_node,
319 ACPI_TYPE_METHOD, next_walk_state);
320 if (ACPI_FAILURE (status)) {
321 goto cleanup;
322 }
323
324
325 /*
326 * Initialize the arguments for the method. The resolved
327 * arguments were put on the previous walk state's operand
328 * stack. Operands on the previous walk state stack always
329 * start at index 0.
330 */
331 status = acpi_ds_method_data_init_args (&this_walk_state->operands[0],
332 this_walk_state->num_operands,
333 next_walk_state);
334 if (ACPI_FAILURE (status)) {
335 goto cleanup;
336 }
337
338
339 /* Create and init a Root Node */
340
341 op = acpi_ps_alloc_op (AML_SCOPE_OP);
342 if (!op) {
343 return_ACPI_STATUS (AE_NO_MEMORY);
344 }
345
346 status = acpi_ps_parse_aml (op, obj_desc->method.pcode,
347 obj_desc->method.pcode_length,
348 ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE,
349 method_node, NULL, NULL,
350 acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
351 acpi_ps_delete_parse_tree (op);
352
353
354 /*
355 * Delete the operands on the previous walkstate operand stack
356 * (they were copied to new objects)
357 */
358 for (i = 0; i < obj_desc->method.param_count; i++) {
359 acpi_ut_remove_reference (this_walk_state->operands [i]);
360 this_walk_state->operands [i] = NULL;
361 }
362
363 /* Clear the operand stack */
364
365 this_walk_state->num_operands = 0;
366
367
368 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Starting nested execution, newstate=%p\n",
369 next_walk_state));
370
371 return_ACPI_STATUS (AE_OK);
372
373
374 /* On error, we must delete the new walk state */
375
376 cleanup:
377 acpi_ds_terminate_control_method (next_walk_state);
378 acpi_ds_delete_walk_state (next_walk_state);
379 return_ACPI_STATUS (status);
380
381 }
382
383
384 /*******************************************************************************
385 *
386 * FUNCTION: Acpi_ds_restart_control_method
387 *
388 * PARAMETERS: Walk_state - State of the method when it was preempted
389 * Op - Pointer to new current op
390 *
391 * RETURN: Status
392 *
393 * DESCRIPTION: Restart a method that was preempted
394 *
395 ******************************************************************************/
396
397 acpi_status
398 acpi_ds_restart_control_method (
399 acpi_walk_state *walk_state,
400 acpi_operand_object *return_desc)
401 {
402 acpi_status status;
403
404
405 FUNCTION_TRACE_PTR ("Ds_restart_control_method", walk_state);
406
407
408 if (return_desc) {
409 if (walk_state->return_used) {
410 /*
411 * Get the return value (if any) from the previous method.
412 * NULL if no return value
413 */
414 status = acpi_ds_result_push (return_desc, walk_state);
415 if (ACPI_FAILURE (status)) {
416 acpi_ut_remove_reference (return_desc);
417 return_ACPI_STATUS (status);
418 }
419 }
420
421 else {
422 /*
423 * Delete the return value if it will not be used by the
424 * calling method
425 */
426 acpi_ut_remove_reference (return_desc);
427 }
428
429 }
430
431 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
432 "Method=%p Return=%p Return_used?=%X Res_stack=%p State=%p\n",
433 walk_state->method_call_op, return_desc, walk_state->return_used,
434 walk_state->results, walk_state));
435
436
437 return_ACPI_STATUS (AE_OK);
438 }
439
440
441 /*******************************************************************************
442 *
443 * FUNCTION: Acpi_ds_terminate_control_method
444 *
445 * PARAMETERS: Walk_state - State of the method
446 *
447 * RETURN: Status
448 *
449 * DESCRIPTION: Terminate a control method. Delete everything that the method
450 * created, delete all locals and arguments, and delete the parse
451 * tree if requested.
452 *
453 ******************************************************************************/
454
455 acpi_status
456 acpi_ds_terminate_control_method (
457 acpi_walk_state *walk_state)
458 {
459 acpi_operand_object *obj_desc;
460 acpi_namespace_node *method_node;
461
462
463 FUNCTION_TRACE_PTR ("Ds_terminate_control_method", walk_state);
464
465
466 /* The method object should be stored in the walk state */
467
468 obj_desc = walk_state->method_desc;
469 if (!obj_desc) {
470 return_ACPI_STATUS (AE_OK);
471 }
472
473 /* Delete all arguments and locals */
474
475 acpi_ds_method_data_delete_all (walk_state);
476
477 /*
478 * Lock the parser while we terminate this method.
479 * If this is the last thread executing the method,
480 * we have additional cleanup to perform
481 */
482 acpi_ut_acquire_mutex (ACPI_MTX_PARSER);
483
484
485 /* Signal completion of the execution of this method if necessary */
486
487 if (walk_state->method_desc->method.semaphore) {
488 acpi_os_signal_semaphore (
489 walk_state->method_desc->method.semaphore, 1);
490 }
491
492 /* Decrement the thread count on the method parse tree */
493
494 walk_state->method_desc->method.thread_count--;
495 if (!walk_state->method_desc->method.thread_count) {
496 /*
497 * There are no more threads executing this method. Perform
498 * additional cleanup.
499 *
500 * The method Node is stored in the walk state
501 */
502 method_node = walk_state->method_node;
503
504 /*
505 * Delete any namespace entries created immediately underneath
506 * the method
507 */
508 acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
509 if (method_node->child) {
510 acpi_ns_delete_namespace_subtree (method_node);
511 }
512
513 /*
514 * Delete any namespace entries created anywhere else within
515 * the namespace
516 */
517 acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id);
518 acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
519 }
520
521 acpi_ut_release_mutex (ACPI_MTX_PARSER);
522 return_ACPI_STATUS (AE_OK);
523 }
524
525
526