dsmethod.c 21.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
 *
 *****************************************************************************/

/*
B
Bob Moore 已提交
8
 * Copyright (C) 2000 - 2006, R. Byron Moore
L
Linus Torvalds 已提交
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
#include <acpi/acparser.h>
#include <acpi/amlcode.h>
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
B
Bob Moore 已提交
50
#include <acpi/acdisasm.h>
L
Linus Torvalds 已提交
51 52

#define _COMPONENT          ACPI_DISPATCHER
L
Len Brown 已提交
53
ACPI_MODULE_NAME("dsmethod")
L
Linus Torvalds 已提交
54

B
Bob Moore 已提交
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_method_error
 *
 * PARAMETERS:  Status          - Execution status
 *              walk_state      - Current state
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Called on method error. Invoke the global exception handler if
 *              present, dump the method data if the disassembler is configured
 *
 *              Note: Allows the exception handler to change the status code
 *
 ******************************************************************************/
acpi_status
acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
{
	ACPI_FUNCTION_ENTRY();

	/* Ignore AE_OK and control exception codes */

	if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
		return (status);
	}

	/* Invoke the global exception handler */

	if (acpi_gbl_exception_handler) {
B
Bob Moore 已提交
84

B
Bob Moore 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
		/* Exit the interpreter, allow handler to execute methods */

		acpi_ex_exit_interpreter();

		/*
		 * Handler can map the exception code to anything it wants, including
		 * AE_OK, in which case the executing method will not be aborted.
		 */
		status = acpi_gbl_exception_handler(status,
						    walk_state->method_node ?
						    walk_state->method_node->
						    name.integer : 0,
						    walk_state->opcode,
						    walk_state->aml_offset,
						    NULL);
		(void)acpi_ex_enter_interpreter();
	}
#ifdef ACPI_DISASSEMBLER
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
104

B
Bob Moore 已提交
105 106 107 108 109 110 111 112 113
		/* Display method locals/args if disassembler is present */

		acpi_dm_dump_method_info(status, walk_state, walk_state->op);
	}
#endif

	return (status);
}

L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_begin_method_execution
 *
 * PARAMETERS:  method_node         - Node of the method
 *              obj_desc            - The method object
 *              calling_method_node - Caller of this method (if non-null)
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Prepare a method for execution.  Parses the method if necessary,
 *              increments the thread count, and waits at the method semaphore
 *              for clearance to execute.
 *
 ******************************************************************************/
B
Bob Moore 已提交
129

L
Linus Torvalds 已提交
130
acpi_status
B
Bob Moore 已提交
131 132 133
acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
			       union acpi_operand_object * obj_desc,
			       struct acpi_namespace_node * calling_method_node)
L
Linus Torvalds 已提交
134
{
L
Len Brown 已提交
135
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
136

B
Bob Moore 已提交
137
	ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
L
Linus Torvalds 已提交
138 139

	if (!method_node) {
L
Len Brown 已提交
140
		return_ACPI_STATUS(AE_NULL_ENTRY);
L
Linus Torvalds 已提交
141 142
	}

R
Robert Moore 已提交
143 144 145
	/* Prevent wraparound of thread count */

	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
B
Bob Moore 已提交
146 147
		ACPI_ERROR((AE_INFO,
			    "Method reached maximum reentrancy limit (255)"));
R
Robert Moore 已提交
148 149 150
		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
	}

L
Linus Torvalds 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164
	/*
	 * If there is a concurrency limit on this method, we need to
	 * obtain a unit from the method semaphore.
	 */
	if (obj_desc->method.semaphore) {
		/*
		 * Allow recursive method calls, up to the reentrancy/concurrency
		 * limit imposed by the SERIALIZED rule and the sync_level method
		 * parameter.
		 *
		 * The point of this code is to avoid permanently blocking a
		 * thread that is making recursive method calls.
		 */
		if (method_node == calling_method_node) {
L
Len Brown 已提交
165 166 167
			if (obj_desc->method.thread_count >=
			    obj_desc->method.concurrency) {
				return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
L
Linus Torvalds 已提交
168 169 170 171 172
			}
		}

		/*
		 * Get a unit from the method semaphore. This releases the
B
Bob Moore 已提交
173
		 * interpreter if we block (then reacquires it)
L
Linus Torvalds 已提交
174
		 */
L
Len Brown 已提交
175 176 177
		status =
		    acpi_ex_system_wait_semaphore(obj_desc->method.semaphore,
						  ACPI_WAIT_FOREVER);
B
Bob Moore 已提交
178 179 180
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
L
Linus Torvalds 已提交
181 182
	}

R
Robert Moore 已提交
183 184 185 186 187 188 189 190
	/*
	 * Allocate an Owner ID for this method, only if this is the first thread
	 * to begin concurrent execution. We only need one owner_id, even if the
	 * method is invoked recursively.
	 */
	if (!obj_desc->method.owner_id) {
		status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
191
			goto cleanup;
R
Robert Moore 已提交
192 193 194
		}
	}

L
Linus Torvalds 已提交
195 196 197 198 199
	/*
	 * Increment the method parse tree thread count since it has been
	 * reentered one more time (even if it is the same thread)
	 */
	obj_desc->method.thread_count++;
L
Len Brown 已提交
200
	return_ACPI_STATUS(status);
B
Bob Moore 已提交
201 202 203 204 205 206 207 208

      cleanup:
	/* On error, must signal the method semaphore if present */

	if (obj_desc->method.semaphore) {
		(void)acpi_os_signal_semaphore(obj_desc->method.semaphore, 1);
	}
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_call_control_method
 *
 * PARAMETERS:  Thread              - Info for this thread
 *              this_walk_state     - Current walk state
 *              Op                  - Current Op to be walked
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Transfer execution to a called control method
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
226 227 228
acpi_ds_call_control_method(struct acpi_thread_state *thread,
			    struct acpi_walk_state *this_walk_state,
			    union acpi_parse_object *op)
L
Linus Torvalds 已提交
229
{
L
Len Brown 已提交
230 231 232 233
	acpi_status status;
	struct acpi_namespace_node *method_node;
	struct acpi_walk_state *next_walk_state = NULL;
	union acpi_operand_object *obj_desc;
B
Bob Moore 已提交
234
	struct acpi_evaluate_info *info;
L
Len Brown 已提交
235
	u32 i;
L
Linus Torvalds 已提交
236

B
Bob Moore 已提交
237
	ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
L
Linus Torvalds 已提交
238

L
Len Brown 已提交
239 240 241
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
			  "Execute method %p, currentstate=%p\n",
			  this_walk_state->prev_op, this_walk_state));
L
Linus Torvalds 已提交
242 243 244 245 246 247

	/*
	 * Get the namespace entry for the control method we are about to call
	 */
	method_node = this_walk_state->method_call_node;
	if (!method_node) {
L
Len Brown 已提交
248
		return_ACPI_STATUS(AE_NULL_ENTRY);
L
Linus Torvalds 已提交
249 250
	}

L
Len Brown 已提交
251
	obj_desc = acpi_ns_get_attached_object(method_node);
L
Linus Torvalds 已提交
252
	if (!obj_desc) {
L
Len Brown 已提交
253
		return_ACPI_STATUS(AE_NULL_OBJECT);
L
Linus Torvalds 已提交
254 255
	}

B
Bob Moore 已提交
256
	/* Init for new method, possibly wait on concurrency semaphore */
L
Linus Torvalds 已提交
257

L
Len Brown 已提交
258 259 260
	status = acpi_ds_begin_method_execution(method_node, obj_desc,
						this_walk_state->method_node);
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
261
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
262 263
	}

B
Bob Moore 已提交
264 265 266 267
	/*
	 * 1) Parse the method. All "normal" methods are parsed for each execution.
	 * Internal methods (_OSI, etc.) do not require parsing.
	 */
L
Linus Torvalds 已提交
268
	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
B
Bob Moore 已提交
269

B
Bob Moore 已提交
270
		/* Create a new walk state for the parse */
L
Linus Torvalds 已提交
271

L
Len Brown 已提交
272 273 274
		next_walk_state =
		    acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
					      obj_desc, NULL);
L
Linus Torvalds 已提交
275
		if (!next_walk_state) {
B
Bob Moore 已提交
276 277
			status = AE_NO_MEMORY;
			goto cleanup;
L
Linus Torvalds 已提交
278 279
		}

B
Bob Moore 已提交
280
		/* Create and init a parse tree root */
L
Linus Torvalds 已提交
281

L
Len Brown 已提交
282
		op = acpi_ps_create_scope_op();
L
Linus Torvalds 已提交
283 284 285 286 287
		if (!op) {
			status = AE_NO_MEMORY;
			goto cleanup;
		}

L
Len Brown 已提交
288 289 290 291 292
		status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
					       obj_desc->method.aml_start,
					       obj_desc->method.aml_length,
					       NULL, 1);
		if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
293
			acpi_ps_delete_parse_tree(op);
L
Linus Torvalds 已提交
294 295 296
			goto cleanup;
		}

B
Bob Moore 已提交
297
		/* Begin AML parse (deletes next_walk_state) */
L
Linus Torvalds 已提交
298

L
Len Brown 已提交
299 300
		status = acpi_ps_parse_aml(next_walk_state);
		acpi_ps_delete_parse_tree(op);
B
Bob Moore 已提交
301 302 303
		if (ACPI_FAILURE(status)) {
			goto cleanup;
		}
L
Linus Torvalds 已提交
304 305
	}

B
Bob Moore 已提交
306
	/* 2) Begin method execution. Create a new walk state */
L
Linus Torvalds 已提交
307

L
Len Brown 已提交
308 309
	next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
						    NULL, obj_desc, thread);
L
Linus Torvalds 已提交
310 311 312 313
	if (!next_walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}
B
Bob Moore 已提交
314

L
Linus Torvalds 已提交
315 316
	/*
	 * The resolved arguments were put on the previous walk state's operand
R
Robert Moore 已提交
317 318
	 * stack. Operands on the previous walk state stack always
	 * start at index 0. Also, null terminate the list of arguments
L
Linus Torvalds 已提交
319
	 */
L
Len Brown 已提交
320
	this_walk_state->operands[this_walk_state->num_operands] = NULL;
L
Linus Torvalds 已提交
321

B
Bob Moore 已提交
322 323 324 325 326 327 328 329 330 331 332 333
	/*
	 * Allocate and initialize the evaluation information block
	 * TBD: this is somewhat inefficient, should change interface to
	 * ds_init_aml_walk. For now, keeps this struct off the CPU stack
	 */
	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
	if (!info) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	info->parameters = &this_walk_state->operands[0];
	info->parameter_type = ACPI_PARAM_ARGS;
L
Linus Torvalds 已提交
334

L
Len Brown 已提交
335 336
	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
				       obj_desc->method.aml_start,
B
Bob Moore 已提交
337 338 339
				       obj_desc->method.aml_length, info, 3);

	ACPI_FREE(info);
L
Len Brown 已提交
340
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
341 342 343 344 345 346 347 348
		goto cleanup;
	}

	/*
	 * Delete the operands on the previous walkstate operand stack
	 * (they were copied to new objects)
	 */
	for (i = 0; i < obj_desc->method.param_count; i++) {
L
Len Brown 已提交
349 350
		acpi_ut_remove_reference(this_walk_state->operands[i]);
		this_walk_state->operands[i] = NULL;
L
Linus Torvalds 已提交
351 352 353 354 355 356
	}

	/* Clear the operand stack */

	this_walk_state->num_operands = 0;

L
Len Brown 已提交
357 358 359
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
			  "Starting nested execution, newstate=%p\n",
			  next_walk_state));
L
Linus Torvalds 已提交
360

B
Bob Moore 已提交
361 362
	/* Invoke an internal method if necessary */

L
Linus Torvalds 已提交
363
	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
L
Len Brown 已提交
364
		status = obj_desc->method.implementation(next_walk_state);
L
Linus Torvalds 已提交
365 366
	}

R
Robert Moore 已提交
367
	return_ACPI_STATUS(status);
L
Len Brown 已提交
368 369 370

      cleanup:

B
Bob Moore 已提交
371
	/* On error, we must terminate the method properly */
R
Robert Moore 已提交
372

B
Bob Moore 已提交
373 374 375 376
	acpi_ds_terminate_control_method(obj_desc, next_walk_state);
	if (next_walk_state) {
		acpi_ds_delete_walk_state(next_walk_state);
	}
R
Robert Moore 已提交
377

L
Len Brown 已提交
378
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_restart_control_method
 *
 * PARAMETERS:  walk_state          - State for preempted method (caller)
 *              return_desc         - Return value from the called method
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Restart a method that was preempted by another (nested) method
 *              invocation.  Handle the return value (if any) from the callee.
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
396 397
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
			       union acpi_operand_object *return_desc)
L
Linus Torvalds 已提交
398
{
L
Len Brown 已提交
399
	acpi_status status;
B
Bob Moore 已提交
400
	int same_as_implicit_return;
L
Linus Torvalds 已提交
401

B
Bob Moore 已提交
402
	ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
L
Linus Torvalds 已提交
403

L
Len Brown 已提交
404
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
405
			  "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
L
Len Brown 已提交
406 407
			  (char *)&walk_state->method_node->name,
			  walk_state->method_call_op, return_desc));
L
Linus Torvalds 已提交
408

L
Len Brown 已提交
409
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
410
			  "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
L
Len Brown 已提交
411 412
			  walk_state->return_used,
			  walk_state->results, walk_state));
L
Linus Torvalds 已提交
413 414 415 416

	/* Did the called method return a value? */

	if (return_desc) {
B
Bob Moore 已提交
417

B
Bob Moore 已提交
418 419 420 421 422
		/* Is the implicit return object the same as the return desc? */

		same_as_implicit_return =
		    (walk_state->implicit_return_obj == return_desc);

L
Linus Torvalds 已提交
423 424 425
		/* Are we actually going to use the return value? */

		if (walk_state->return_used) {
B
Bob Moore 已提交
426

L
Linus Torvalds 已提交
427 428
			/* Save the return value from the previous method */

L
Len Brown 已提交
429 430 431 432
			status = acpi_ds_result_push(return_desc, walk_state);
			if (ACPI_FAILURE(status)) {
				acpi_ut_remove_reference(return_desc);
				return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
433 434 435 436 437 438 439 440 441 442
			}

			/*
			 * Save as THIS method's return value in case it is returned
			 * immediately to yet another method
			 */
			walk_state->return_desc = return_desc;
		}

		/*
B
Bob Moore 已提交
443 444 445 446 447 448 449
		 * The following code is the optional support for the so-called
		 * "implicit return". Some AML code assumes that the last value of the
		 * method is "implicitly" returned to the caller, in the absence of an
		 * explicit return value.
		 *
		 * Just save the last result of the method as the return value.
		 *
L
Linus Torvalds 已提交
450 451 452
		 * NOTE: this is optional because the ASL language does not actually
		 * support this behavior.
		 */
L
Len Brown 已提交
453
		else if (!acpi_ds_do_implicit_return
B
Bob Moore 已提交
454 455
			 (return_desc, walk_state, FALSE)
			 || same_as_implicit_return) {
L
Linus Torvalds 已提交
456 457
			/*
			 * Delete the return value if it will not be used by the
B
Bob Moore 已提交
458 459
			 * calling method or remove one reference if the explicit return
			 * is the same as the implicit return value.
L
Linus Torvalds 已提交
460
			 */
L
Len Brown 已提交
461
			acpi_ut_remove_reference(return_desc);
L
Linus Torvalds 已提交
462 463 464
		}
	}

L
Len Brown 已提交
465
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
466 467 468 469 470 471
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_terminate_control_method
 *
B
Bob Moore 已提交
472 473
 * PARAMETERS:  method_desc         - Method object
 *              walk_state          - State associated with the method
L
Linus Torvalds 已提交
474
 *
R
Robert Moore 已提交
475
 * RETURN:      None
L
Linus Torvalds 已提交
476 477 478 479 480 481 482
 *
 * DESCRIPTION: Terminate a control method.  Delete everything that the method
 *              created, delete all locals and arguments, and delete the parse
 *              tree if requested.
 *
 ******************************************************************************/

B
Bob Moore 已提交
483 484 485
void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
				 struct acpi_walk_state *walk_state)
L
Linus Torvalds 已提交
486
{
L
Len Brown 已提交
487 488
	struct acpi_namespace_node *method_node;
	acpi_status status;
L
Linus Torvalds 已提交
489

B
Bob Moore 已提交
490
	ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
L
Linus Torvalds 已提交
491

B
Bob Moore 已提交
492
	/* method_desc is required, walk_state is optional */
L
Linus Torvalds 已提交
493

B
Bob Moore 已提交
494
	if (!method_desc) {
R
Robert Moore 已提交
495
		return_VOID;
L
Linus Torvalds 已提交
496 497
	}

B
Bob Moore 已提交
498
	if (walk_state) {
L
Linus Torvalds 已提交
499

B
Bob Moore 已提交
500 501 502 503
		/* Delete all arguments and locals */

		acpi_ds_method_data_delete_all(walk_state);
	}
L
Linus Torvalds 已提交
504 505 506 507 508 509

	/*
	 * Lock the parser while we terminate this method.
	 * If this is the last thread executing the method,
	 * we have additional cleanup to perform
	 */
B
Bob Moore 已提交
510
	status = acpi_ut_acquire_mutex(ACPI_MTX_CONTROL_METHOD);
L
Len Brown 已提交
511
	if (ACPI_FAILURE(status)) {
R
Robert Moore 已提交
512
		return_VOID;
L
Linus Torvalds 已提交
513 514 515 516
	}

	/* Signal completion of the execution of this method if necessary */

B
Bob Moore 已提交
517
	if (method_desc->method.semaphore) {
L
Len Brown 已提交
518
		status =
B
Bob Moore 已提交
519
		    acpi_os_signal_semaphore(method_desc->method.semaphore, 1);
L
Len Brown 已提交
520
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
521

B
Bob Moore 已提交
522 523 524 525
			/* Ignore error and continue */

			ACPI_EXCEPTION((AE_INFO, status,
					"Could not signal method semaphore"));
L
Linus Torvalds 已提交
526 527 528
		}
	}

B
Bob Moore 已提交
529 530 531 532 533 534
	if (walk_state) {
		/*
		 * Delete any objects created by this method during execution.
		 * The method Node is stored in the walk state
		 */
		method_node = walk_state->method_node;
B
Bob Moore 已提交
535

B
Bob Moore 已提交
536
		/* Lock namespace for possible update */
B
Bob Moore 已提交
537

B
Bob Moore 已提交
538 539 540 541
		status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
		if (ACPI_FAILURE(status)) {
			goto exit;
		}
B
Bob Moore 已提交
542

B
Bob Moore 已提交
543 544 545 546 547 548 549 550 551 552 553 554 555 556
		/*
		 * Delete any namespace entries created immediately underneath
		 * the method
		 */
		if (method_node && method_node->child) {
			acpi_ns_delete_namespace_subtree(method_node);
		}

		/*
		 * Delete any namespace entries created anywhere else within
		 * the namespace by the execution of this method
		 */
		acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
		status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
B
Bob Moore 已提交
557 558
	}

B
Bob Moore 已提交
559 560 561 562 563 564 565
	/* Decrement the thread count on the method */

	if (method_desc->method.thread_count) {
		method_desc->method.thread_count--;
	} else {
		ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
	}
B
Bob Moore 已提交
566 567 568

	/* Are there any other threads currently executing this method? */

B
Bob Moore 已提交
569
	if (method_desc->method.thread_count) {
B
Bob Moore 已提交
570 571 572 573
		/*
		 * Additional threads. Do not release the owner_id in this case,
		 * we immediately reuse it for the next thread executing this method
		 */
L
Len Brown 已提交
574
		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
575
				  "*** Completed execution of one thread, %d threads remaining\n",
B
Bob Moore 已提交
576
				  method_desc->method.thread_count));
B
Bob Moore 已提交
577 578
	} else {
		/* This is the only executing thread for this method */
L
Linus Torvalds 已提交
579 580 581

		/*
		 * Support to dynamically change a method from not_serialized to
B
Bob Moore 已提交
582
		 * Serialized if it appears that the method is incorrectly written and
L
Linus Torvalds 已提交
583 584 585 586 587 588 589
		 * 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
		 *
		 * This code is here because we must wait until the last thread exits
		 * before creating the synchronization semaphore.
		 */
B
Bob Moore 已提交
590 591
		if ((method_desc->method.concurrency == 1) &&
		    (!method_desc->method.semaphore)) {
L
Len Brown 已提交
592
			status = acpi_os_create_semaphore(1, 1,
B
Bob Moore 已提交
593
							  &method_desc->method.
L
Len Brown 已提交
594
							  semaphore);
L
Linus Torvalds 已提交
595 596
		}

B
Bob Moore 已提交
597
		/* No more threads, we can free the owner_id */
L
Linus Torvalds 已提交
598

B
Bob Moore 已提交
599
		acpi_ut_release_owner_id(&method_desc->method.owner_id);
L
Linus Torvalds 已提交
600
	}
L
Len Brown 已提交
601

R
Robert Moore 已提交
602
      exit:
B
Bob Moore 已提交
603
	(void)acpi_ut_release_mutex(ACPI_MTX_CONTROL_METHOD);
R
Robert Moore 已提交
604
	return_VOID;
L
Linus Torvalds 已提交
605
}
B
Bob Moore 已提交
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635

#ifdef ACPI_INIT_PARSE_METHODS
	/*
	 * Note 11/2005: Removed this code to parse all methods during table
	 * load because it causes problems if there are any errors during the
	 * parse. Also, it seems like overkill and we probably don't want to
	 * abort a table load because of an issue with a single method.
	 */

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_parse_method
 *
 * PARAMETERS:  Node        - Method node
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Parse the AML that is associated with the method.
 *
 * MUTEX:       Assumes parser is locked
 *
 ******************************************************************************/

acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
{
	acpi_status status;
	union acpi_operand_object *obj_desc;
	union acpi_parse_object *op;
	struct acpi_walk_state *walk_state;

B
Bob Moore 已提交
636
	ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node);
B
Bob Moore 已提交
637 638 639 640 641 642 643 644

	/* Parameter Validation */

	if (!node) {
		return_ACPI_STATUS(AE_NULL_ENTRY);
	}

	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
B
Bob Moore 已提交
645
			  "**** Parsing [%4.4s] **** NamedObj=%p\n",
B
Bob Moore 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
			  acpi_ut_get_node_name(node), node));

	/* Extract the method object from the method Node */

	obj_desc = acpi_ns_get_attached_object(node);
	if (!obj_desc) {
		return_ACPI_STATUS(AE_NULL_OBJECT);
	}

	/* Create a mutex for the method if there is a concurrency limit */

	if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
	    (!obj_desc->method.semaphore)) {
		status = acpi_os_create_semaphore(obj_desc->method.concurrency,
						  obj_desc->method.concurrency,
						  &obj_desc->method.semaphore);
		if (ACPI_FAILURE(status)) {
			return_ACPI_STATUS(status);
		}
	}

	/*
	 * Allocate a new parser op to be the root of the parsed
	 * method tree
	 */
	op = acpi_ps_alloc_op(AML_METHOD_OP);
	if (!op) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/* Init new op with the method name and pointer back to the Node */

	acpi_ps_set_name(op, node->name.integer);
	op->common.node = node;

	/*
	 * Get a new owner_id for objects created by this method. Namespace
	 * objects (such as Operation Regions) can be created during the
	 * first pass parse.
	 */
	status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
	if (ACPI_FAILURE(status)) {
		goto cleanup;
	}

	/* Create and initialize a new walk state */

	walk_state =
	    acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
				      NULL);
	if (!walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup2;
	}

	status = acpi_ds_init_aml_walk(walk_state, op, node,
				       obj_desc->method.aml_start,
				       obj_desc->method.aml_length, NULL, 1);
	if (ACPI_FAILURE(status)) {
		acpi_ds_delete_walk_state(walk_state);
		goto cleanup2;
	}

	/*
	 * Parse the method, first pass
	 *
	 * The first pass load is where newly declared named objects are added into
	 * the namespace.  Actual evaluation of the named objects (what would be
	 * called a "second pass") happens during the actual execution of the
	 * method so that operands to the named objects can take on dynamic
	 * run-time values.
	 */
	status = acpi_ps_parse_aml(walk_state);
	if (ACPI_FAILURE(status)) {
		goto cleanup2;
	}

	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
B
Bob Moore 已提交
724
			  "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n",
B
Bob Moore 已提交
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
			  acpi_ut_get_node_name(node), node, op));

	/*
	 * Delete the parse tree. We simply re-parse the method for every
	 * execution since there isn't much overhead (compared to keeping lots
	 * of parse trees around)
	 */
	acpi_ns_delete_namespace_subtree(node);
	acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);

      cleanup2:
	acpi_ut_release_owner_id(&obj_desc->method.owner_id);

      cleanup:
	acpi_ps_delete_parse_tree(op);
	return_ACPI_STATUS(status);
}
#endif