dsmethod.c 18.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7
/******************************************************************************
 *
 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
 *
 *****************************************************************************/

/*
8
 * Copyright (C) 2000 - 2007, R. Byron Moore
Linus Torvalds's avatar
Linus Torvalds committed
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>
Bob Moore's avatar
Bob Moore committed
50
#include <acpi/acdisasm.h>
Linus Torvalds's avatar
Linus Torvalds committed
51 52

#define _COMPONENT          ACPI_DISPATCHER
Len Brown's avatar
Len Brown committed
53
ACPI_MODULE_NAME("dsmethod")
Linus Torvalds's avatar
Linus Torvalds committed
54

Bob Moore's avatar
Bob Moore committed
55 56 57 58
/* Local prototypes */
static acpi_status
acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);

Bob Moore's avatar
Bob Moore committed
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
 *
 ******************************************************************************/
Bob Moore's avatar
Bob Moore committed
74

Bob Moore's avatar
Bob Moore committed
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) {
Bob Moore's avatar
Bob Moore committed
89

Bob Moore's avatar
Bob Moore committed
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)) {
Bob Moore's avatar
Bob Moore committed
109

Bob Moore's avatar
Bob Moore committed
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);
}

Bob Moore's avatar
Bob Moore committed
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;

Bob Moore's avatar
Bob Moore committed
137
	ACPI_FUNCTION_TRACE(ds_create_method_mutex);
Bob Moore's avatar
Bob Moore committed
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);
}

Linus Torvalds's avatar
Linus Torvalds committed
158 159 160 161 162 163
/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_begin_method_execution
 *
 * PARAMETERS:  method_node         - Node of the method
 *              obj_desc            - The method object
Bob Moore's avatar
Bob Moore committed
164 165
 *              walk_state          - current state, NULL if not yet executing
 *                                    a method.
Linus Torvalds's avatar
Linus Torvalds committed
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.
 *
 ******************************************************************************/
Bob Moore's avatar
Bob Moore committed
174

Linus Torvalds's avatar
Linus Torvalds committed
175
acpi_status
Bob Moore's avatar
Bob Moore committed
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)
Linus Torvalds's avatar
Linus Torvalds committed
179
{
Len Brown's avatar
Len Brown committed
180
	acpi_status status = AE_OK;
Linus Torvalds's avatar
Linus Torvalds committed
181

Bob Moore's avatar
Bob Moore committed
182
	ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
Linus Torvalds's avatar
Linus Torvalds committed
183 184

	if (!method_node) {
Len Brown's avatar
Len Brown committed
185
		return_ACPI_STATUS(AE_NULL_ENTRY);
Linus Torvalds's avatar
Linus Torvalds committed
186 187
	}

Robert Moore's avatar
Robert Moore committed
188 189 190
	/* Prevent wraparound of thread count */

	if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
Bob Moore's avatar
Bob Moore committed
191 192
		ACPI_ERROR((AE_INFO,
			    "Method reached maximum reentrancy limit (255)"));
Robert Moore's avatar
Robert Moore committed
193 194 195
		return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
	}

Linus Torvalds's avatar
Linus Torvalds committed
196
	/*
Bob Moore's avatar
Bob Moore committed
197
	 * If this method is serialized, we need to acquire the method mutex.
Linus Torvalds's avatar
Linus Torvalds committed
198
	 */
Bob Moore's avatar
Bob Moore committed
199
	if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
Linus Torvalds's avatar
Linus Torvalds committed
200
		/*
Bob Moore's avatar
Bob Moore committed
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
Linus Torvalds's avatar
Linus Torvalds committed
204
		 */
Bob Moore's avatar
Bob Moore committed
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);
Linus Torvalds's avatar
Linus Torvalds committed
209 210 211 212
			}
		}

		/*
Bob Moore's avatar
Bob Moore committed
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
Linus Torvalds's avatar
Linus Torvalds committed
218
		 */
Bob Moore's avatar
Bob Moore committed
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);
Bob Moore's avatar
Bob Moore committed
228
		}
Bob Moore's avatar
Bob Moore committed
229 230 231 232 233

		/*
		 * Obtain the method mutex if necessary. Do not acquire mutex for a
		 * recursive call.
		 */
234 235 236 237
		if (!walk_state ||
		    !obj_desc->method.mutex->mutex.owner_thread ||
		    (walk_state->thread !=
		     obj_desc->method.mutex->mutex.owner_thread)) {
Bob Moore's avatar
Bob Moore committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
			/*
			 * 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;

257 258
				obj_desc->method.mutex->mutex.owner_thread =
				    walk_state->thread;
Bob Moore's avatar
Bob Moore committed
259 260 261 262 263 264 265 266 267 268 269 270
				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++;
Linus Torvalds's avatar
Linus Torvalds committed
271 272
	}

Robert Moore's avatar
Robert Moore committed
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)) {
Bob Moore's avatar
Bob Moore committed
281
			goto cleanup;
Robert Moore's avatar
Robert Moore committed
282 283 284
		}
	}

Linus Torvalds's avatar
Linus Torvalds committed
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++;
Len Brown's avatar
Len Brown committed
290
	return_ACPI_STATUS(status);
Bob Moore's avatar
Bob Moore committed
291 292

      cleanup:
Bob Moore's avatar
Bob Moore committed
293
	/* On error, must release the method mutex (if present) */
Bob Moore's avatar
Bob Moore committed
294

Bob Moore's avatar
Bob Moore committed
295 296
	if (obj_desc->method.mutex) {
		acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
Bob Moore's avatar
Bob Moore committed
297 298
	}
	return_ACPI_STATUS(status);
Linus Torvalds's avatar
Linus Torvalds committed
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
Len Brown's avatar
Len Brown committed
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)
Linus Torvalds's avatar
Linus Torvalds committed
319
{
Len Brown's avatar
Len Brown committed
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;
Bob Moore's avatar
Bob Moore committed
324
	struct acpi_evaluate_info *info;
Len Brown's avatar
Len Brown committed
325
	u32 i;
Linus Torvalds's avatar
Linus Torvalds committed
326

Bob Moore's avatar
Bob Moore committed
327
	ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
Linus Torvalds's avatar
Linus Torvalds committed
328

Len Brown's avatar
Len Brown committed
329
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
330
			  "Calling method %p, currentstate=%p\n",
Len Brown's avatar
Len Brown committed
331
			  this_walk_state->prev_op, this_walk_state));
Linus Torvalds's avatar
Linus Torvalds committed
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) {
Len Brown's avatar
Len Brown committed
338
		return_ACPI_STATUS(AE_NULL_ENTRY);
Linus Torvalds's avatar
Linus Torvalds committed
339 340
	}

Len Brown's avatar
Len Brown committed
341
	obj_desc = acpi_ns_get_attached_object(method_node);
Linus Torvalds's avatar
Linus Torvalds committed
342
	if (!obj_desc) {
Len Brown's avatar
Len Brown committed
343
		return_ACPI_STATUS(AE_NULL_OBJECT);
Linus Torvalds's avatar
Linus Torvalds committed
344 345
	}

Bob Moore's avatar
Bob Moore committed
346
	/* Init for new method, possibly wait on method mutex */
Linus Torvalds's avatar
Linus Torvalds committed
347

Len Brown's avatar
Len Brown committed
348
	status = acpi_ds_begin_method_execution(method_node, obj_desc,
Bob Moore's avatar
Bob Moore committed
349
						this_walk_state);
Len Brown's avatar
Len Brown committed
350
	if (ACPI_FAILURE(status)) {
Bob Moore's avatar
Bob Moore committed
351
		return_ACPI_STATUS(status);
Linus Torvalds's avatar
Linus Torvalds committed
352 353
	}

354
	/* Begin method parse/execution. Create a new walk state */
Linus Torvalds's avatar
Linus Torvalds committed
355

Len Brown's avatar
Len Brown committed
356 357
	next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
						    NULL, obj_desc, thread);
Linus Torvalds's avatar
Linus Torvalds committed
358 359 360 361
	if (!next_walk_state) {
		status = AE_NO_MEMORY;
		goto cleanup;
	}
Bob Moore's avatar
Bob Moore committed
362

Linus Torvalds's avatar
Linus Torvalds committed
363 364
	/*
	 * The resolved arguments were put on the previous walk state's operand
Robert Moore's avatar
Robert Moore committed
365 366
	 * stack. Operands on the previous walk state stack always
	 * start at index 0. Also, null terminate the list of arguments
Linus Torvalds's avatar
Linus Torvalds committed
367
	 */
Len Brown's avatar
Len Brown committed
368
	this_walk_state->operands[this_walk_state->num_operands] = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
369

Bob Moore's avatar
Bob Moore committed
370 371 372 373 374 375 376 377 378 379 380 381
	/*
	 * 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;
Linus Torvalds's avatar
Linus Torvalds committed
382

Len Brown's avatar
Len Brown committed
383 384
	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
				       obj_desc->method.aml_start,
385 386
				       obj_desc->method.aml_length, info,
				       ACPI_IMODE_EXECUTE);
Bob Moore's avatar
Bob Moore committed
387 388

	ACPI_FREE(info);
Len Brown's avatar
Len Brown committed
389
	if (ACPI_FAILURE(status)) {
Linus Torvalds's avatar
Linus Torvalds committed
390 391 392 393 394 395 396 397
		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++) {
Len Brown's avatar
Len Brown committed
398 399
		acpi_ut_remove_reference(this_walk_state->operands[i]);
		this_walk_state->operands[i] = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
400 401 402 403 404 405
	}

	/* Clear the operand stack */

	this_walk_state->num_operands = 0;

Len Brown's avatar
Len Brown committed
406
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
407 408
			  "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
			  method_node->name.ascii, next_walk_state));
Linus Torvalds's avatar
Linus Torvalds committed
409

Bob Moore's avatar
Bob Moore committed
410 411
	/* Invoke an internal method if necessary */

Linus Torvalds's avatar
Linus Torvalds committed
412
	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
Len Brown's avatar
Len Brown committed
413
		status = obj_desc->method.implementation(next_walk_state);
Linus Torvalds's avatar
Linus Torvalds committed
414 415
	}

Robert Moore's avatar
Robert Moore committed
416
	return_ACPI_STATUS(status);
Len Brown's avatar
Len Brown committed
417 418 419

      cleanup:

Bob Moore's avatar
Bob Moore committed
420
	/* On error, we must terminate the method properly */
Robert Moore's avatar
Robert Moore committed
421

Bob Moore's avatar
Bob Moore committed
422 423 424 425
	acpi_ds_terminate_control_method(obj_desc, next_walk_state);
	if (next_walk_state) {
		acpi_ds_delete_walk_state(next_walk_state);
	}
Robert Moore's avatar
Robert Moore committed
426

Len Brown's avatar
Len Brown committed
427
	return_ACPI_STATUS(status);
Linus Torvalds's avatar
Linus Torvalds committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
}

/*******************************************************************************
 *
 * 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
Len Brown's avatar
Len Brown committed
445 446
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
			       union acpi_operand_object *return_desc)
Linus Torvalds's avatar
Linus Torvalds committed
447
{
Len Brown's avatar
Len Brown committed
448
	acpi_status status;
Bob Moore's avatar
Bob Moore committed
449
	int same_as_implicit_return;
Linus Torvalds's avatar
Linus Torvalds committed
450

Bob Moore's avatar
Bob Moore committed
451
	ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
Linus Torvalds's avatar
Linus Torvalds committed
452

Len Brown's avatar
Len Brown committed
453
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
Bob Moore's avatar
Bob Moore committed
454
			  "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
Bob Moore's avatar
Bob Moore committed
455
			  acpi_ut_get_node_name(walk_state->method_node),
Len Brown's avatar
Len Brown committed
456
			  walk_state->method_call_op, return_desc));
Linus Torvalds's avatar
Linus Torvalds committed
457

Len Brown's avatar
Len Brown committed
458
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
Bob Moore's avatar
Bob Moore committed
459
			  "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
Len Brown's avatar
Len Brown committed
460 461
			  walk_state->return_used,
			  walk_state->results, walk_state));
Linus Torvalds's avatar
Linus Torvalds committed
462 463 464 465

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

	if (return_desc) {
Bob Moore's avatar
Bob Moore committed
466

Bob Moore's avatar
Bob Moore committed
467 468 469 470 471
		/* Is the implicit return object the same as the return desc? */

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

Linus Torvalds's avatar
Linus Torvalds committed
472 473 474
		/* Are we actually going to use the return value? */

		if (walk_state->return_used) {
Bob Moore's avatar
Bob Moore committed
475

Linus Torvalds's avatar
Linus Torvalds committed
476 477
			/* Save the return value from the previous method */

Len Brown's avatar
Len Brown committed
478 479 480 481
			status = acpi_ds_result_push(return_desc, walk_state);
			if (ACPI_FAILURE(status)) {
				acpi_ut_remove_reference(return_desc);
				return_ACPI_STATUS(status);
Linus Torvalds's avatar
Linus Torvalds committed
482 483 484 485 486 487 488 489 490 491
			}

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

		/*
Bob Moore's avatar
Bob Moore committed
492 493 494 495 496 497 498
		 * 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.
		 *
Linus Torvalds's avatar
Linus Torvalds committed
499 500 501
		 * NOTE: this is optional because the ASL language does not actually
		 * support this behavior.
		 */
Len Brown's avatar
Len Brown committed
502
		else if (!acpi_ds_do_implicit_return
Bob Moore's avatar
Bob Moore committed
503 504
			 (return_desc, walk_state, FALSE)
			 || same_as_implicit_return) {
Linus Torvalds's avatar
Linus Torvalds committed
505 506
			/*
			 * Delete the return value if it will not be used by the
Bob Moore's avatar
Bob Moore committed
507 508
			 * calling method or remove one reference if the explicit return
			 * is the same as the implicit return value.
Linus Torvalds's avatar
Linus Torvalds committed
509
			 */
Len Brown's avatar
Len Brown committed
510
			acpi_ut_remove_reference(return_desc);
Linus Torvalds's avatar
Linus Torvalds committed
511 512 513
		}
	}

Len Brown's avatar
Len Brown committed
514
	return_ACPI_STATUS(AE_OK);
Linus Torvalds's avatar
Linus Torvalds committed
515 516 517 518 519 520
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_terminate_control_method
 *
Bob Moore's avatar
Bob Moore committed
521 522
 * PARAMETERS:  method_desc         - Method object
 *              walk_state          - State associated with the method
Linus Torvalds's avatar
Linus Torvalds committed
523
 *
Robert Moore's avatar
Robert Moore committed
524
 * RETURN:      None
Linus Torvalds's avatar
Linus Torvalds committed
525 526 527 528 529
 *
 * DESCRIPTION: Terminate a control method.  Delete everything that the method
 *              created, delete all locals and arguments, and delete the parse
 *              tree if requested.
 *
Bob Moore's avatar
Bob Moore committed
530 531
 * MUTEX:       Interpreter is locked
 *
Linus Torvalds's avatar
Linus Torvalds committed
532 533
 ******************************************************************************/

Bob Moore's avatar
Bob Moore committed
534 535 536
void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
				 struct acpi_walk_state *walk_state)
Linus Torvalds's avatar
Linus Torvalds committed
537
{
Len Brown's avatar
Len Brown committed
538 539
	struct acpi_namespace_node *method_node;
	acpi_status status;
Linus Torvalds's avatar
Linus Torvalds committed
540

Bob Moore's avatar
Bob Moore committed
541
	ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
Linus Torvalds's avatar
Linus Torvalds committed
542

Bob Moore's avatar
Bob Moore committed
543
	/* method_desc is required, walk_state is optional */
Linus Torvalds's avatar
Linus Torvalds committed
544

Bob Moore's avatar
Bob Moore committed
545
	if (!method_desc) {
Robert Moore's avatar
Robert Moore committed
546
		return_VOID;
Linus Torvalds's avatar
Linus Torvalds committed
547 548
	}

Bob Moore's avatar
Bob Moore committed
549
	if (walk_state) {
Linus Torvalds's avatar
Linus Torvalds committed
550

Bob Moore's avatar
Bob Moore committed
551 552 553 554
		/* Delete all arguments and locals */

		acpi_ds_method_data_delete_all(walk_state);
	}
Linus Torvalds's avatar
Linus Torvalds committed
555 556

	/*
Bob Moore's avatar
Bob Moore committed
557 558
	 * If method is serialized, release the mutex and restore the
	 * current sync level for this thread
Linus Torvalds's avatar
Linus Torvalds committed
559
	 */
Bob Moore's avatar
Bob Moore committed
560
	if (method_desc->method.mutex) {
Linus Torvalds's avatar
Linus Torvalds committed
561

Bob Moore's avatar
Bob Moore committed
562
		/* Acquisition Depth handles recursive calls */
Linus Torvalds's avatar
Linus Torvalds committed
563

Bob Moore's avatar
Bob Moore committed
564 565 566 567 568
		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;
Bob Moore's avatar
Bob Moore committed
569

Bob Moore's avatar
Bob Moore committed
570 571
			acpi_os_release_mutex(method_desc->method.mutex->mutex.
					      os_mutex);
572
			method_desc->method.mutex->mutex.owner_thread = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
573 574 575
		}
	}

Bob Moore's avatar
Bob Moore committed
576 577 578 579 580 581
	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;
Bob Moore's avatar
Bob Moore committed
582

Bob Moore's avatar
Bob Moore committed
583
		/*
Bob Moore's avatar
Bob Moore committed
584
		 * Delete any namespace objects created anywhere within
Bob Moore's avatar
Bob Moore committed
585 586 587
		 * the namespace by the execution of this method
		 */
		acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
Bob Moore's avatar
Bob Moore committed
588 589
	}

Bob Moore's avatar
Bob Moore committed
590 591 592 593 594 595 596
	/* 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"));
	}
Bob Moore's avatar
Bob Moore committed
597 598 599

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

Bob Moore's avatar
Bob Moore committed
600
	if (method_desc->method.thread_count) {
Bob Moore's avatar
Bob Moore committed
601 602 603 604
		/*
		 * Additional threads. Do not release the owner_id in this case,
		 * we immediately reuse it for the next thread executing this method
		 */
Len Brown's avatar
Len Brown committed
605
		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
Bob Moore's avatar
Bob Moore committed
606
				  "*** Completed execution of one thread, %d threads remaining\n",
Bob Moore's avatar
Bob Moore committed
607
				  method_desc->method.thread_count));
Bob Moore's avatar
Bob Moore committed
608 609
	} else {
		/* This is the only executing thread for this method */
Linus Torvalds's avatar
Linus Torvalds committed
610 611 612

		/*
		 * Support to dynamically change a method from not_serialized to
Bob Moore's avatar
Bob Moore committed
613
		 * Serialized if it appears that the method is incorrectly written and
Bob Moore's avatar
Bob Moore committed
614 615
		 * does not support multiple thread execution. The best example of this
		 * is if such a method creates namespace objects and blocks. A second
Linus Torvalds's avatar
Linus Torvalds committed
616 617 618 619 620
		 * 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.
		 */
Bob Moore's avatar
Bob Moore committed
621 622 623
		if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
		    && (!method_desc->method.mutex)) {
			status = acpi_ds_create_method_mutex(method_desc);
Linus Torvalds's avatar
Linus Torvalds committed
624 625
		}

Bob Moore's avatar
Bob Moore committed
626
		/* No more threads, we can free the owner_id */
Linus Torvalds's avatar
Linus Torvalds committed
627

Bob Moore's avatar
Bob Moore committed
628
		acpi_ut_release_owner_id(&method_desc->method.owner_id);
Linus Torvalds's avatar
Linus Torvalds committed
629
	}
Len Brown's avatar
Len Brown committed
630

Robert Moore's avatar
Robert Moore committed
631
	return_VOID;
Linus Torvalds's avatar
Linus Torvalds committed
632
}