dsmethod.c 19.8 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
/* Local prototypes */
static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);

B
Bob Moore 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
/*******************************************************************************
 *
 * 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
 *
 ******************************************************************************/
B
Bob Moore 已提交
74

B
Bob Moore 已提交
75 76 77 78 79 80 81 82 83 84 85 86 87 88
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 已提交
89

B
Bob Moore 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
		/* 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 已提交
109

B
Bob Moore 已提交
110 111 112 113 114 115 116 117 118
		/* Display method locals/args if disassembler is present */

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

	return (status);
}

B
Bob Moore 已提交
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_create_method_mutex
 *
 * PARAMETERS:  obj_desc            - The method object
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Create a mutex object for a serialized control method
 *
 ******************************************************************************/

static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
{
	union acpi_operand_object *mutex_desc;
	acpi_status status;

B
Bob Moore 已提交
137
	ACPI_FUNCTION_TRACE(ds_create_method_mutex);
B
Bob Moore 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157

	/* Create the new mutex object */

	mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
	if (!mutex_desc) {
		return_ACPI_STATUS(AE_NO_MEMORY);
	}

	/* Create the actual OS Mutex */

	status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
	if (ACPI_FAILURE(status)) {
		return_ACPI_STATUS(status);
	}

	mutex_desc->mutex.sync_level = method_desc->method.sync_level;
	method_desc->method.mutex = mutex_desc;
	return_ACPI_STATUS(AE_OK);
}

L
Linus Torvalds 已提交
158 159 160 161 162 163
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_begin_method_execution
 *
 * PARAMETERS:  method_node         - Node of the method
 *              obj_desc            - The method object
B
Bob Moore 已提交
164 165
 *              walk_state          - current state, NULL if not yet executing
 *                                    a method.
L
Linus Torvalds 已提交
166 167 168 169 170 171 172 173
 *
 * 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 已提交
174

L
Linus Torvalds 已提交
175
acpi_status
B
Bob Moore 已提交
176 177 178
acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
			       union acpi_operand_object *obj_desc,
			       struct acpi_walk_state *walk_state)
L
Linus Torvalds 已提交
179
{
L
Len Brown 已提交
180
	acpi_status status = AE_OK;
L
Linus Torvalds 已提交
181

B
Bob Moore 已提交
182
	ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
L
Linus Torvalds 已提交
183 184

	if (!method_node) {
L
Len Brown 已提交
185
		return_ACPI_STATUS(AE_NULL_ENTRY);
L
Linus Torvalds 已提交
186 187
	}

R
Robert Moore 已提交
188 189 190
	/* Prevent wraparound of thread count */

	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
B
Bob Moore 已提交
191 192
		ACPI_ERROR((AE_INFO,
			    "Method reached maximum reentrancy limit (255)"));
R
Robert Moore 已提交
193 194 195
		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
	}

L
Linus Torvalds 已提交
196
	/*
B
Bob Moore 已提交
197
	 * If this method is serialized, we need to acquire the method mutex.
L
Linus Torvalds 已提交
198
	 */
B
Bob Moore 已提交
199
	if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
L
Linus Torvalds 已提交
200
		/*
B
Bob Moore 已提交
201 202 203
		 * Create a mutex for the method if it is defined to be Serialized
		 * and a mutex has not already been created. We defer the mutex creation
		 * until a method is actually executed, to minimize the object count
L
Linus Torvalds 已提交
204
		 */
B
Bob Moore 已提交
205 206 207 208
		if (!obj_desc->method.mutex) {
			status = acpi_ds_create_method_mutex(obj_desc);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
209 210 211 212
			}
		}

		/*
B
Bob Moore 已提交
213 214 215 216 217
		 * 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
		 *
		 * Top-level method invocation has no walk state at this point
L
Linus Torvalds 已提交
218
		 */
B
Bob Moore 已提交
219 220 221 222 223 224 225 226 227
		if (walk_state &&
		    (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 (%d)",
				    acpi_ut_get_node_name(method_node),
				    walk_state->thread->current_sync_level));

			return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
B
Bob Moore 已提交
228
		}
B
Bob Moore 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270

		/*
		 * Obtain the method mutex if necessary. Do not acquire mutex for a
		 * recursive call.
		 */
		if (!walk_state ||
		    !obj_desc->method.mutex->mutex.owner_thread ||
		    (walk_state->thread !=
		     obj_desc->method.mutex->mutex.owner_thread)) {
			/*
			 * Acquire the method mutex. This releases the interpreter if we
			 * block (and reacquires it before it returns)
			 */
			status =
			    acpi_ex_system_wait_mutex(obj_desc->method.mutex->
						      mutex.os_mutex,
						      ACPI_WAIT_FOREVER);
			if (ACPI_FAILURE(status)) {
				return_ACPI_STATUS(status);
			}

			/* Update the mutex and walk info and save the original sync_level */

			if (walk_state) {
				obj_desc->method.mutex->mutex.
				    original_sync_level =
				    walk_state->thread->current_sync_level;

				obj_desc->method.mutex->mutex.owner_thread =
				    walk_state->thread;
				walk_state->thread->current_sync_level =
				    obj_desc->method.sync_level;
			} else {
				obj_desc->method.mutex->mutex.
				    original_sync_level =
				    obj_desc->method.mutex->mutex.sync_level;
			}
		}

		/* Always increase acquisition depth */

		obj_desc->method.mutex->mutex.acquisition_depth++;
L
Linus Torvalds 已提交
271 272
	}

R
Robert Moore 已提交
273 274 275 276 277 278 279 280
	/*
	 * 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 已提交
281
			goto cleanup;
R
Robert Moore 已提交
282 283 284
		}
	}

L
Linus Torvalds 已提交
285 286 287 288 289
	/*
	 * 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 已提交
290
	return_ACPI_STATUS(status);
B
Bob Moore 已提交
291 292

      cleanup:
B
Bob Moore 已提交
293
	/* On error, must release the method mutex (if present) */
B
Bob Moore 已提交
294

B
Bob Moore 已提交
295 296
	if (obj_desc->method.mutex) {
		acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
B
Bob Moore 已提交
297 298
	}
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
}

/*******************************************************************************
 *
 * 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 已提交
316 317 318
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 已提交
319
{
L
Len Brown 已提交
320 321 322 323
	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 已提交
324
	struct acpi_evaluate_info *info;
L
Len Brown 已提交
325
	u32 i;
L
Linus Torvalds 已提交
326

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

L
Len Brown 已提交
329 330 331
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
			  "Execute method %p, currentstate=%p\n",
			  this_walk_state->prev_op, this_walk_state));
L
Linus Torvalds 已提交
332 333 334 335 336 337

	/*
	 * 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 已提交
338
		return_ACPI_STATUS(AE_NULL_ENTRY);
L
Linus Torvalds 已提交
339 340
	}

L
Len Brown 已提交
341
	obj_desc = acpi_ns_get_attached_object(method_node);
L
Linus Torvalds 已提交
342
	if (!obj_desc) {
L
Len Brown 已提交
343
		return_ACPI_STATUS(AE_NULL_OBJECT);
L
Linus Torvalds 已提交
344 345
	}

B
Bob Moore 已提交
346
	/* Init for new method, possibly wait on method mutex */
L
Linus Torvalds 已提交
347

L
Len Brown 已提交
348
	status = acpi_ds_begin_method_execution(method_node, obj_desc,
B
Bob Moore 已提交
349
						this_walk_state);
L
Len Brown 已提交
350
	if (ACPI_FAILURE(status)) {
B
Bob Moore 已提交
351
		return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
352 353
	}

B
Bob Moore 已提交
354 355 356 357
	/*
	 * 1) Parse the method. All "normal" methods are parsed for each execution.
	 * Internal methods (_OSI, etc.) do not require parsing.
	 */
L
Linus Torvalds 已提交
358
	if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
B
Bob Moore 已提交
359

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

L
Len Brown 已提交
362 363 364
		next_walk_state =
		    acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
					      obj_desc, NULL);
L
Linus Torvalds 已提交
365
		if (!next_walk_state) {
B
Bob Moore 已提交
366 367
			status = AE_NO_MEMORY;
			goto cleanup;
L
Linus Torvalds 已提交
368 369
		}

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

L
Len Brown 已提交
372
		op = acpi_ps_create_scope_op();
L
Linus Torvalds 已提交
373 374 375 376 377
		if (!op) {
			status = AE_NO_MEMORY;
			goto cleanup;
		}

L
Len Brown 已提交
378 379 380 381 382
		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 已提交
383
			acpi_ps_delete_parse_tree(op);
L
Linus Torvalds 已提交
384 385 386
			goto cleanup;
		}

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

L
Len Brown 已提交
389 390
		status = acpi_ps_parse_aml(next_walk_state);
		acpi_ps_delete_parse_tree(op);
B
Bob Moore 已提交
391 392 393
		if (ACPI_FAILURE(status)) {
			goto cleanup;
		}
L
Linus Torvalds 已提交
394 395
	}

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

L
Len Brown 已提交
398 399
	next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
						    NULL, obj_desc, thread);
L
Linus Torvalds 已提交
400 401 402 403
	if (!next_walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}
B
Bob Moore 已提交
404

L
Linus Torvalds 已提交
405 406
	/*
	 * The resolved arguments were put on the previous walk state's operand
R
Robert Moore 已提交
407 408
	 * stack. Operands on the previous walk state stack always
	 * start at index 0. Also, null terminate the list of arguments
L
Linus Torvalds 已提交
409
	 */
L
Len Brown 已提交
410
	this_walk_state->operands[this_walk_state->num_operands] = NULL;
L
Linus Torvalds 已提交
411

B
Bob Moore 已提交
412 413 414 415 416 417 418 419 420 421 422 423
	/*
	 * 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 已提交
424

L
Len Brown 已提交
425 426
	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
				       obj_desc->method.aml_start,
B
Bob Moore 已提交
427 428 429
				       obj_desc->method.aml_length, info, 3);

	ACPI_FREE(info);
L
Len Brown 已提交
430
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
431 432 433 434 435 436 437 438
		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 已提交
439 440
		acpi_ut_remove_reference(this_walk_state->operands[i]);
		this_walk_state->operands[i] = NULL;
L
Linus Torvalds 已提交
441 442 443 444 445 446
	}

	/* Clear the operand stack */

	this_walk_state->num_operands = 0;

L
Len Brown 已提交
447 448 449
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
			  "Starting nested execution, newstate=%p\n",
			  next_walk_state));
L
Linus Torvalds 已提交
450

B
Bob Moore 已提交
451 452
	/* Invoke an internal method if necessary */

L
Linus Torvalds 已提交
453
	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
L
Len Brown 已提交
454
		status = obj_desc->method.implementation(next_walk_state);
L
Linus Torvalds 已提交
455 456
	}

R
Robert Moore 已提交
457
	return_ACPI_STATUS(status);
L
Len Brown 已提交
458 459 460

      cleanup:

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

B
Bob Moore 已提交
463 464 465 466
	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 已提交
467

L
Len Brown 已提交
468
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
}

/*******************************************************************************
 *
 * 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 已提交
486 487
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
			       union acpi_operand_object *return_desc)
L
Linus Torvalds 已提交
488
{
L
Len Brown 已提交
489
	acpi_status status;
B
Bob Moore 已提交
490
	int same_as_implicit_return;
L
Linus Torvalds 已提交
491

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

L
Len Brown 已提交
494
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
495
			  "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
B
Bob Moore 已提交
496
			  acpi_ut_get_node_name(walk_state->method_node),
L
Len Brown 已提交
497
			  walk_state->method_call_op, return_desc));
L
Linus Torvalds 已提交
498

L
Len Brown 已提交
499
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
500
			  "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
L
Len Brown 已提交
501 502
			  walk_state->return_used,
			  walk_state->results, walk_state));
L
Linus Torvalds 已提交
503 504 505 506

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

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

B
Bob Moore 已提交
508 509 510 511 512
		/* 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 已提交
513 514 515
		/* Are we actually going to use the return value? */

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

L
Linus Torvalds 已提交
517 518
			/* Save the return value from the previous method */

L
Len Brown 已提交
519 520 521 522
			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 已提交
523 524 525 526 527 528 529 530 531 532
			}

			/*
			 * 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 已提交
533 534 535 536 537 538 539
		 * 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 已提交
540 541 542
		 * NOTE: this is optional because the ASL language does not actually
		 * support this behavior.
		 */
L
Len Brown 已提交
543
		else if (!acpi_ds_do_implicit_return
B
Bob Moore 已提交
544 545
			 (return_desc, walk_state, FALSE)
			 || same_as_implicit_return) {
L
Linus Torvalds 已提交
546 547
			/*
			 * Delete the return value if it will not be used by the
B
Bob Moore 已提交
548 549
			 * calling method or remove one reference if the explicit return
			 * is the same as the implicit return value.
L
Linus Torvalds 已提交
550
			 */
L
Len Brown 已提交
551
			acpi_ut_remove_reference(return_desc);
L
Linus Torvalds 已提交
552 553 554
		}
	}

L
Len Brown 已提交
555
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
556 557 558 559 560 561
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_terminate_control_method
 *
B
Bob Moore 已提交
562 563
 * PARAMETERS:  method_desc         - Method object
 *              walk_state          - State associated with the method
L
Linus Torvalds 已提交
564
 *
R
Robert Moore 已提交
565
 * RETURN:      None
L
Linus Torvalds 已提交
566 567 568 569 570
 *
 * 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 已提交
571 572
 * MUTEX:       Interpreter is locked
 *
L
Linus Torvalds 已提交
573 574
 ******************************************************************************/

B
Bob Moore 已提交
575 576 577
void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
				 struct acpi_walk_state *walk_state)
L
Linus Torvalds 已提交
578
{
L
Len Brown 已提交
579 580
	struct acpi_namespace_node *method_node;
	acpi_status status;
L
Linus Torvalds 已提交
581

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

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

B
Bob Moore 已提交
586
	if (!method_desc) {
R
Robert Moore 已提交
587
		return_VOID;
L
Linus Torvalds 已提交
588 589
	}

B
Bob Moore 已提交
590
	if (walk_state) {
L
Linus Torvalds 已提交
591

B
Bob Moore 已提交
592 593 594 595
		/* Delete all arguments and locals */

		acpi_ds_method_data_delete_all(walk_state);
	}
L
Linus Torvalds 已提交
596 597

	/*
B
Bob Moore 已提交
598 599
	 * If method is serialized, release the mutex and restore the
	 * current sync level for this thread
L
Linus Torvalds 已提交
600
	 */
B
Bob Moore 已提交
601
	if (method_desc->method.mutex) {
L
Linus Torvalds 已提交
602

B
Bob Moore 已提交
603
		/* Acquisition Depth handles recursive calls */
L
Linus Torvalds 已提交
604

B
Bob Moore 已提交
605 606 607 608 609
		method_desc->method.mutex->mutex.acquisition_depth--;
		if (!method_desc->method.mutex->mutex.acquisition_depth) {
			walk_state->thread->current_sync_level =
			    method_desc->method.mutex->mutex.
			    original_sync_level;
B
Bob Moore 已提交
610

B
Bob Moore 已提交
611 612
			acpi_os_release_mutex(method_desc->method.mutex->mutex.
					      os_mutex);
B
Bob Moore 已提交
613
			method_desc->method.mutex->mutex.owner_thread = NULL;
L
Linus Torvalds 已提交
614 615 616
		}
	}

B
Bob Moore 已提交
617 618 619 620 621 622
	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 已提交
623

B
Bob Moore 已提交
624
		/*
B
Bob Moore 已提交
625
		 * Delete any namespace objects created anywhere within
B
Bob Moore 已提交
626 627 628
		 * the namespace by the execution of this method
		 */
		acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
B
Bob Moore 已提交
629 630
	}

B
Bob Moore 已提交
631 632 633 634 635 636 637
	/* 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 已提交
638 639 640

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

B
Bob Moore 已提交
641
	if (method_desc->method.thread_count) {
B
Bob Moore 已提交
642 643 644 645
		/*
		 * 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 已提交
646
		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
647
				  "*** Completed execution of one thread, %d threads remaining\n",
B
Bob Moore 已提交
648
				  method_desc->method.thread_count));
B
Bob Moore 已提交
649 650
	} else {
		/* This is the only executing thread for this method */
L
Linus Torvalds 已提交
651 652 653

		/*
		 * Support to dynamically change a method from not_serialized to
B
Bob Moore 已提交
654
		 * Serialized if it appears that the method is incorrectly written and
B
Bob Moore 已提交
655 656
		 * does not support multiple thread execution. The best example of this
		 * is if such a method creates namespace objects and blocks. A second
L
Linus Torvalds 已提交
657 658 659 660 661
		 * 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 已提交
662 663 664
		if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
		    && (!method_desc->method.mutex)) {
			status = acpi_ds_create_method_mutex(method_desc);
L
Linus Torvalds 已提交
665 666
		}

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

B
Bob Moore 已提交
669
		acpi_ut_release_owner_id(&method_desc->method.owner_id);
L
Linus Torvalds 已提交
670
	}
L
Len Brown 已提交
671

R
Robert Moore 已提交
672
	return_VOID;
L
Linus Torvalds 已提交
673
}