dsmethod.c 21.1 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 234 235
	acpi_status status;
	struct acpi_namespace_node *method_node;
	struct acpi_walk_state *next_walk_state = NULL;
	union acpi_operand_object *obj_desc;
	struct acpi_parameter_info info;
	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 322 323 324

	info.parameters = &this_walk_state->operands[0];
	info.parameter_type = ACPI_PARAM_ARGS;

L
Len Brown 已提交
325 326 327 328
	status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
				       obj_desc->method.aml_start,
				       obj_desc->method.aml_length, &info, 3);
	if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
329 330 331 332 333 334 335 336
		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 已提交
337 338
		acpi_ut_remove_reference(this_walk_state->operands[i]);
		this_walk_state->operands[i] = NULL;
L
Linus Torvalds 已提交
339 340 341 342 343 344
	}

	/* Clear the operand stack */

	this_walk_state->num_operands = 0;

L
Len Brown 已提交
345 346 347
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
			  "Starting nested execution, newstate=%p\n",
			  next_walk_state));
L
Linus Torvalds 已提交
348

B
Bob Moore 已提交
349 350
	/* Invoke an internal method if necessary */

L
Linus Torvalds 已提交
351
	if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
L
Len Brown 已提交
352
		status = obj_desc->method.implementation(next_walk_state);
L
Linus Torvalds 已提交
353 354
	}

R
Robert Moore 已提交
355
	return_ACPI_STATUS(status);
L
Len Brown 已提交
356 357 358

      cleanup:

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

B
Bob Moore 已提交
361 362 363 364
	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 已提交
365

L
Len Brown 已提交
366
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
}

/*******************************************************************************
 *
 * 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 已提交
384 385
acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
			       union acpi_operand_object *return_desc)
L
Linus Torvalds 已提交
386
{
L
Len Brown 已提交
387
	acpi_status status;
B
Bob Moore 已提交
388
	int same_as_implicit_return;
L
Linus Torvalds 已提交
389

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

L
Len Brown 已提交
392
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
393
			  "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
L
Len Brown 已提交
394 395
			  (char *)&walk_state->method_node->name,
			  walk_state->method_call_op, return_desc));
L
Linus Torvalds 已提交
396

L
Len Brown 已提交
397
	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
398
			  "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
L
Len Brown 已提交
399 400
			  walk_state->return_used,
			  walk_state->results, walk_state));
L
Linus Torvalds 已提交
401 402 403 404

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

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

B
Bob Moore 已提交
406 407 408 409 410
		/* 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 已提交
411 412 413
		/* Are we actually going to use the return value? */

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

L
Linus Torvalds 已提交
415 416
			/* Save the return value from the previous method */

L
Len Brown 已提交
417 418 419 420
			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 已提交
421 422 423 424 425 426 427 428 429 430
			}

			/*
			 * 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 已提交
431 432 433 434 435 436 437
		 * 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 已提交
438 439 440
		 * NOTE: this is optional because the ASL language does not actually
		 * support this behavior.
		 */
L
Len Brown 已提交
441
		else if (!acpi_ds_do_implicit_return
B
Bob Moore 已提交
442 443
			 (return_desc, walk_state, FALSE)
			 || same_as_implicit_return) {
L
Linus Torvalds 已提交
444 445
			/*
			 * Delete the return value if it will not be used by the
B
Bob Moore 已提交
446 447
			 * calling method or remove one reference if the explicit return
			 * is the same as the implicit return value.
L
Linus Torvalds 已提交
448
			 */
L
Len Brown 已提交
449
			acpi_ut_remove_reference(return_desc);
L
Linus Torvalds 已提交
450 451 452
		}
	}

L
Len Brown 已提交
453
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
454 455 456 457 458 459
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ds_terminate_control_method
 *
B
Bob Moore 已提交
460 461
 * PARAMETERS:  method_desc         - Method object
 *              walk_state          - State associated with the method
L
Linus Torvalds 已提交
462
 *
R
Robert Moore 已提交
463
 * RETURN:      None
L
Linus Torvalds 已提交
464 465 466 467 468 469 470
 *
 * 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 已提交
471 472 473
void
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
				 struct acpi_walk_state *walk_state)
L
Linus Torvalds 已提交
474
{
L
Len Brown 已提交
475 476
	struct acpi_namespace_node *method_node;
	acpi_status status;
L
Linus Torvalds 已提交
477

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

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

B
Bob Moore 已提交
482
	if (!method_desc) {
R
Robert Moore 已提交
483
		return_VOID;
L
Linus Torvalds 已提交
484 485
	}

B
Bob Moore 已提交
486
	if (walk_state) {
L
Linus Torvalds 已提交
487

B
Bob Moore 已提交
488 489 490 491
		/* Delete all arguments and locals */

		acpi_ds_method_data_delete_all(walk_state);
	}
L
Linus Torvalds 已提交
492 493 494 495 496 497

	/*
	 * Lock the parser while we terminate this method.
	 * If this is the last thread executing the method,
	 * we have additional cleanup to perform
	 */
L
Len Brown 已提交
498 499
	status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER);
	if (ACPI_FAILURE(status)) {
R
Robert Moore 已提交
500
		return_VOID;
L
Linus Torvalds 已提交
501 502 503 504
	}

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

B
Bob Moore 已提交
505
	if (method_desc->method.semaphore) {
L
Len Brown 已提交
506
		status =
B
Bob Moore 已提交
507
		    acpi_os_signal_semaphore(method_desc->method.semaphore, 1);
L
Len Brown 已提交
508
		if (ACPI_FAILURE(status)) {
L
Linus Torvalds 已提交
509

B
Bob Moore 已提交
510 511 512 513
			/* Ignore error and continue */

			ACPI_EXCEPTION((AE_INFO, status,
					"Could not signal method semaphore"));
L
Linus Torvalds 已提交
514 515 516
		}
	}

B
Bob Moore 已提交
517 518 519 520 521 522
	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 已提交
523

B
Bob Moore 已提交
524
		/* Lock namespace for possible update */
B
Bob Moore 已提交
525

B
Bob Moore 已提交
526 527 528 529
		status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
		if (ACPI_FAILURE(status)) {
			goto exit;
		}
B
Bob Moore 已提交
530

B
Bob Moore 已提交
531 532 533 534 535 536 537 538 539 540 541 542 543 544
		/*
		 * 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 已提交
545 546
	}

B
Bob Moore 已提交
547 548 549 550 551 552 553
	/* 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 已提交
554 555 556

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

B
Bob Moore 已提交
557
	if (method_desc->method.thread_count) {
B
Bob Moore 已提交
558 559 560 561
		/*
		 * 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 已提交
562
		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
B
Bob Moore 已提交
563
				  "*** Completed execution of one thread, %d threads remaining\n",
B
Bob Moore 已提交
564
				  method_desc->method.thread_count));
B
Bob Moore 已提交
565 566
	} else {
		/* This is the only executing thread for this method */
L
Linus Torvalds 已提交
567 568 569

		/*
		 * Support to dynamically change a method from not_serialized to
B
Bob Moore 已提交
570
		 * Serialized if it appears that the method is incorrectly written and
L
Linus Torvalds 已提交
571 572 573 574 575 576 577
		 * 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 已提交
578 579
		if ((method_desc->method.concurrency == 1) &&
		    (!method_desc->method.semaphore)) {
L
Len Brown 已提交
580
			status = acpi_os_create_semaphore(1, 1,
B
Bob Moore 已提交
581
							  &method_desc->method.
L
Len Brown 已提交
582
							  semaphore);
L
Linus Torvalds 已提交
583 584
		}

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

B
Bob Moore 已提交
587
		acpi_ut_release_owner_id(&method_desc->method.owner_id);
L
Linus Torvalds 已提交
588
	}
L
Len Brown 已提交
589

R
Robert Moore 已提交
590 591 592
      exit:
	(void)acpi_ut_release_mutex(ACPI_MTX_PARSER);
	return_VOID;
L
Linus Torvalds 已提交
593
}
B
Bob Moore 已提交
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623

#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 已提交
624
	ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node);
B
Bob Moore 已提交
625 626 627 628 629 630 631 632

	/* Parameter Validation */

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

	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
B
Bob Moore 已提交
633
			  "**** Parsing [%4.4s] **** NamedObj=%p\n",
B
Bob Moore 已提交
634 635 636 637 638 639 640 641 642 643 644 645 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
			  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 已提交
712
			  "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n",
B
Bob Moore 已提交
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
			  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