diff options
Diffstat (limited to 'drivers/acpi/dispatcher/dsmethod.c')
-rw-r--r-- | drivers/acpi/dispatcher/dsmethod.c | 180 |
1 files changed, 102 insertions, 78 deletions
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 7dc59fc7344f..651f2b68531b 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c | |||
@@ -134,7 +134,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, | |||
134 | { | 134 | { |
135 | acpi_status status = AE_OK; | 135 | acpi_status status = AE_OK; |
136 | 136 | ||
137 | ACPI_FUNCTION_TRACE_PTR("ds_begin_method_execution", method_node); | 137 | ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); |
138 | 138 | ||
139 | if (!method_node) { | 139 | if (!method_node) { |
140 | return_ACPI_STATUS(AE_NULL_ENTRY); | 140 | return_ACPI_STATUS(AE_NULL_ENTRY); |
@@ -170,11 +170,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, | |||
170 | 170 | ||
171 | /* | 171 | /* |
172 | * Get a unit from the method semaphore. This releases the | 172 | * Get a unit from the method semaphore. This releases the |
173 | * interpreter if we block | 173 | * interpreter if we block (then reacquires it) |
174 | */ | 174 | */ |
175 | status = | 175 | status = |
176 | acpi_ex_system_wait_semaphore(obj_desc->method.semaphore, | 176 | acpi_ex_system_wait_semaphore(obj_desc->method.semaphore, |
177 | ACPI_WAIT_FOREVER); | 177 | ACPI_WAIT_FOREVER); |
178 | if (ACPI_FAILURE(status)) { | ||
179 | return_ACPI_STATUS(status); | ||
180 | } | ||
178 | } | 181 | } |
179 | 182 | ||
180 | /* | 183 | /* |
@@ -185,7 +188,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, | |||
185 | if (!obj_desc->method.owner_id) { | 188 | if (!obj_desc->method.owner_id) { |
186 | status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); | 189 | status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); |
187 | if (ACPI_FAILURE(status)) { | 190 | if (ACPI_FAILURE(status)) { |
188 | return_ACPI_STATUS(status); | 191 | goto cleanup; |
189 | } | 192 | } |
190 | } | 193 | } |
191 | 194 | ||
@@ -195,6 +198,14 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node, | |||
195 | */ | 198 | */ |
196 | obj_desc->method.thread_count++; | 199 | obj_desc->method.thread_count++; |
197 | return_ACPI_STATUS(status); | 200 | return_ACPI_STATUS(status); |
201 | |||
202 | cleanup: | ||
203 | /* On error, must signal the method semaphore if present */ | ||
204 | |||
205 | if (obj_desc->method.semaphore) { | ||
206 | (void)acpi_os_signal_semaphore(obj_desc->method.semaphore, 1); | ||
207 | } | ||
208 | return_ACPI_STATUS(status); | ||
198 | } | 209 | } |
199 | 210 | ||
200 | /******************************************************************************* | 211 | /******************************************************************************* |
@@ -223,7 +234,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
223 | struct acpi_parameter_info info; | 234 | struct acpi_parameter_info info; |
224 | u32 i; | 235 | u32 i; |
225 | 236 | ||
226 | ACPI_FUNCTION_TRACE_PTR("ds_call_control_method", this_walk_state); | 237 | ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state); |
227 | 238 | ||
228 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 239 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
229 | "Execute method %p, currentstate=%p\n", | 240 | "Execute method %p, currentstate=%p\n", |
@@ -242,26 +253,31 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
242 | return_ACPI_STATUS(AE_NULL_OBJECT); | 253 | return_ACPI_STATUS(AE_NULL_OBJECT); |
243 | } | 254 | } |
244 | 255 | ||
245 | /* Init for new method, wait on concurrency semaphore */ | 256 | /* Init for new method, possibly wait on concurrency semaphore */ |
246 | 257 | ||
247 | status = acpi_ds_begin_method_execution(method_node, obj_desc, | 258 | status = acpi_ds_begin_method_execution(method_node, obj_desc, |
248 | this_walk_state->method_node); | 259 | this_walk_state->method_node); |
249 | if (ACPI_FAILURE(status)) { | 260 | if (ACPI_FAILURE(status)) { |
250 | goto cleanup; | 261 | return_ACPI_STATUS(status); |
251 | } | 262 | } |
252 | 263 | ||
264 | /* | ||
265 | * 1) Parse the method. All "normal" methods are parsed for each execution. | ||
266 | * Internal methods (_OSI, etc.) do not require parsing. | ||
267 | */ | ||
253 | if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { | 268 | if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) { |
254 | 269 | ||
255 | /* 1) Parse: Create a new walk state for the preempting walk */ | 270 | /* Create a new walk state for the parse */ |
256 | 271 | ||
257 | next_walk_state = | 272 | next_walk_state = |
258 | acpi_ds_create_walk_state(obj_desc->method.owner_id, op, | 273 | acpi_ds_create_walk_state(obj_desc->method.owner_id, op, |
259 | obj_desc, NULL); | 274 | obj_desc, NULL); |
260 | if (!next_walk_state) { | 275 | if (!next_walk_state) { |
261 | return_ACPI_STATUS(AE_NO_MEMORY); | 276 | status = AE_NO_MEMORY; |
277 | goto cleanup; | ||
262 | } | 278 | } |
263 | 279 | ||
264 | /* Create and init a Root Node */ | 280 | /* Create and init a parse tree root */ |
265 | 281 | ||
266 | op = acpi_ps_create_scope_op(); | 282 | op = acpi_ps_create_scope_op(); |
267 | if (!op) { | 283 | if (!op) { |
@@ -274,17 +290,20 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
274 | obj_desc->method.aml_length, | 290 | obj_desc->method.aml_length, |
275 | NULL, 1); | 291 | NULL, 1); |
276 | if (ACPI_FAILURE(status)) { | 292 | if (ACPI_FAILURE(status)) { |
277 | acpi_ds_delete_walk_state(next_walk_state); | 293 | acpi_ps_delete_parse_tree(op); |
278 | goto cleanup; | 294 | goto cleanup; |
279 | } | 295 | } |
280 | 296 | ||
281 | /* Begin AML parse */ | 297 | /* Begin AML parse (deletes next_walk_state) */ |
282 | 298 | ||
283 | status = acpi_ps_parse_aml(next_walk_state); | 299 | status = acpi_ps_parse_aml(next_walk_state); |
284 | acpi_ps_delete_parse_tree(op); | 300 | acpi_ps_delete_parse_tree(op); |
301 | if (ACPI_FAILURE(status)) { | ||
302 | goto cleanup; | ||
303 | } | ||
285 | } | 304 | } |
286 | 305 | ||
287 | /* 2) Execute: Create a new state for the preempting walk */ | 306 | /* 2) Begin method execution. Create a new walk state */ |
288 | 307 | ||
289 | next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, | 308 | next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id, |
290 | NULL, obj_desc, thread); | 309 | NULL, obj_desc, thread); |
@@ -292,6 +311,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
292 | status = AE_NO_MEMORY; | 311 | status = AE_NO_MEMORY; |
293 | goto cleanup; | 312 | goto cleanup; |
294 | } | 313 | } |
314 | |||
295 | /* | 315 | /* |
296 | * The resolved arguments were put on the previous walk state's operand | 316 | * The resolved arguments were put on the previous walk state's operand |
297 | * stack. Operands on the previous walk state stack always | 317 | * stack. Operands on the previous walk state stack always |
@@ -326,6 +346,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
326 | "Starting nested execution, newstate=%p\n", | 346 | "Starting nested execution, newstate=%p\n", |
327 | next_walk_state)); | 347 | next_walk_state)); |
328 | 348 | ||
349 | /* Invoke an internal method if necessary */ | ||
350 | |||
329 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | 351 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { |
330 | status = obj_desc->method.implementation(next_walk_state); | 352 | status = obj_desc->method.implementation(next_walk_state); |
331 | } | 353 | } |
@@ -333,16 +355,14 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
333 | return_ACPI_STATUS(status); | 355 | return_ACPI_STATUS(status); |
334 | 356 | ||
335 | cleanup: | 357 | cleanup: |
336 | /* Decrement the thread count on the method parse tree */ | ||
337 | 358 | ||
338 | if (next_walk_state && (next_walk_state->method_desc)) { | 359 | /* On error, we must terminate the method properly */ |
339 | next_walk_state->method_desc->method.thread_count--; | ||
340 | } | ||
341 | 360 | ||
342 | /* On error, we must delete the new walk state */ | 361 | acpi_ds_terminate_control_method(obj_desc, next_walk_state); |
362 | if (next_walk_state) { | ||
363 | acpi_ds_delete_walk_state(next_walk_state); | ||
364 | } | ||
343 | 365 | ||
344 | acpi_ds_terminate_control_method(next_walk_state); | ||
345 | acpi_ds_delete_walk_state(next_walk_state); | ||
346 | return_ACPI_STATUS(status); | 366 | return_ACPI_STATUS(status); |
347 | } | 367 | } |
348 | 368 | ||
@@ -366,15 +386,15 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, | |||
366 | { | 386 | { |
367 | acpi_status status; | 387 | acpi_status status; |
368 | 388 | ||
369 | ACPI_FUNCTION_TRACE_PTR("ds_restart_control_method", walk_state); | 389 | ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state); |
370 | 390 | ||
371 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 391 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
372 | "****Restart [%4.4s] Op %p return_value_from_callee %p\n", | 392 | "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", |
373 | (char *)&walk_state->method_node->name, | 393 | (char *)&walk_state->method_node->name, |
374 | walk_state->method_call_op, return_desc)); | 394 | walk_state->method_call_op, return_desc)); |
375 | 395 | ||
376 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 396 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
377 | " return_from_this_method_used?=%X res_stack %p Walk %p\n", | 397 | " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", |
378 | walk_state->return_used, | 398 | walk_state->return_used, |
379 | walk_state->results, walk_state)); | 399 | walk_state->results, walk_state)); |
380 | 400 | ||
@@ -426,7 +446,8 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, | |||
426 | * | 446 | * |
427 | * FUNCTION: acpi_ds_terminate_control_method | 447 | * FUNCTION: acpi_ds_terminate_control_method |
428 | * | 448 | * |
429 | * PARAMETERS: walk_state - State of the method | 449 | * PARAMETERS: method_desc - Method object |
450 | * walk_state - State associated with the method | ||
430 | * | 451 | * |
431 | * RETURN: None | 452 | * RETURN: None |
432 | * | 453 | * |
@@ -436,28 +457,27 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, | |||
436 | * | 457 | * |
437 | ******************************************************************************/ | 458 | ******************************************************************************/ |
438 | 459 | ||
439 | void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | 460 | void |
461 | acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, | ||
462 | struct acpi_walk_state *walk_state) | ||
440 | { | 463 | { |
441 | union acpi_operand_object *obj_desc; | ||
442 | struct acpi_namespace_node *method_node; | 464 | struct acpi_namespace_node *method_node; |
443 | acpi_status status; | 465 | acpi_status status; |
444 | 466 | ||
445 | ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state); | 467 | ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); |
446 | |||
447 | if (!walk_state) { | ||
448 | return_VOID; | ||
449 | } | ||
450 | 468 | ||
451 | /* The current method object was saved in the walk state */ | 469 | /* method_desc is required, walk_state is optional */ |
452 | 470 | ||
453 | obj_desc = walk_state->method_desc; | 471 | if (!method_desc) { |
454 | if (!obj_desc) { | ||
455 | return_VOID; | 472 | return_VOID; |
456 | } | 473 | } |
457 | 474 | ||
458 | /* Delete all arguments and locals */ | 475 | if (walk_state) { |
459 | 476 | ||
460 | acpi_ds_method_data_delete_all(walk_state); | 477 | /* Delete all arguments and locals */ |
478 | |||
479 | acpi_ds_method_data_delete_all(walk_state); | ||
480 | } | ||
461 | 481 | ||
462 | /* | 482 | /* |
463 | * Lock the parser while we terminate this method. | 483 | * Lock the parser while we terminate this method. |
@@ -471,60 +491,66 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | |||
471 | 491 | ||
472 | /* Signal completion of the execution of this method if necessary */ | 492 | /* Signal completion of the execution of this method if necessary */ |
473 | 493 | ||
474 | if (walk_state->method_desc->method.semaphore) { | 494 | if (method_desc->method.semaphore) { |
475 | status = | 495 | status = |
476 | acpi_os_signal_semaphore(walk_state->method_desc->method. | 496 | acpi_os_signal_semaphore(method_desc->method.semaphore, 1); |
477 | semaphore, 1); | ||
478 | if (ACPI_FAILURE(status)) { | 497 | if (ACPI_FAILURE(status)) { |
479 | ACPI_ERROR((AE_INFO, | ||
480 | "Could not signal method semaphore")); | ||
481 | 498 | ||
482 | /* Ignore error and continue cleanup */ | 499 | /* Ignore error and continue */ |
500 | |||
501 | ACPI_EXCEPTION((AE_INFO, status, | ||
502 | "Could not signal method semaphore")); | ||
483 | } | 503 | } |
484 | } | 504 | } |
485 | 505 | ||
486 | /* | 506 | if (walk_state) { |
487 | * There are no more threads executing this method. Perform | 507 | /* |
488 | * additional cleanup. | 508 | * Delete any objects created by this method during execution. |
489 | * | 509 | * The method Node is stored in the walk state |
490 | * The method Node is stored in the walk state | 510 | */ |
491 | */ | 511 | method_node = walk_state->method_node; |
492 | method_node = walk_state->method_node; | ||
493 | 512 | ||
494 | /* Lock namespace for possible update */ | 513 | /* Lock namespace for possible update */ |
495 | 514 | ||
496 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | 515 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); |
497 | if (ACPI_FAILURE(status)) { | 516 | if (ACPI_FAILURE(status)) { |
498 | goto exit; | 517 | goto exit; |
499 | } | 518 | } |
500 | 519 | ||
501 | /* | 520 | /* |
502 | * Delete any namespace entries created immediately underneath | 521 | * Delete any namespace entries created immediately underneath |
503 | * the method | 522 | * the method |
504 | */ | 523 | */ |
505 | if (method_node && method_node->child) { | 524 | if (method_node && method_node->child) { |
506 | acpi_ns_delete_namespace_subtree(method_node); | 525 | acpi_ns_delete_namespace_subtree(method_node); |
526 | } | ||
527 | |||
528 | /* | ||
529 | * Delete any namespace entries created anywhere else within | ||
530 | * the namespace by the execution of this method | ||
531 | */ | ||
532 | acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); | ||
533 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
507 | } | 534 | } |
508 | 535 | ||
509 | /* | 536 | /* Decrement the thread count on the method */ |
510 | * Delete any namespace entries created anywhere else within | 537 | |
511 | * the namespace by the execution of this method | 538 | if (method_desc->method.thread_count) { |
512 | */ | 539 | method_desc->method.thread_count--; |
513 | acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method. | 540 | } else { |
514 | owner_id); | 541 | ACPI_ERROR((AE_INFO, "Invalid zero thread count in method")); |
515 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 542 | } |
516 | 543 | ||
517 | /* Are there any other threads currently executing this method? */ | 544 | /* Are there any other threads currently executing this method? */ |
518 | 545 | ||
519 | if (walk_state->method_desc->method.thread_count) { | 546 | if (method_desc->method.thread_count) { |
520 | /* | 547 | /* |
521 | * Additional threads. Do not release the owner_id in this case, | 548 | * Additional threads. Do not release the owner_id in this case, |
522 | * we immediately reuse it for the next thread executing this method | 549 | * we immediately reuse it for the next thread executing this method |
523 | */ | 550 | */ |
524 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 551 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
525 | "*** Completed execution of one thread, %d threads remaining\n", | 552 | "*** Completed execution of one thread, %d threads remaining\n", |
526 | walk_state->method_desc->method. | 553 | method_desc->method.thread_count)); |
527 | thread_count)); | ||
528 | } else { | 554 | } else { |
529 | /* This is the only executing thread for this method */ | 555 | /* This is the only executing thread for this method */ |
530 | 556 | ||
@@ -538,18 +564,16 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | |||
538 | * This code is here because we must wait until the last thread exits | 564 | * This code is here because we must wait until the last thread exits |
539 | * before creating the synchronization semaphore. | 565 | * before creating the synchronization semaphore. |
540 | */ | 566 | */ |
541 | if ((walk_state->method_desc->method.concurrency == 1) && | 567 | if ((method_desc->method.concurrency == 1) && |
542 | (!walk_state->method_desc->method.semaphore)) { | 568 | (!method_desc->method.semaphore)) { |
543 | status = acpi_os_create_semaphore(1, 1, | 569 | status = acpi_os_create_semaphore(1, 1, |
544 | &walk_state-> | 570 | &method_desc->method. |
545 | method_desc->method. | ||
546 | semaphore); | 571 | semaphore); |
547 | } | 572 | } |
548 | 573 | ||
549 | /* No more threads, we can free the owner_id */ | 574 | /* No more threads, we can free the owner_id */ |
550 | 575 | ||
551 | acpi_ut_release_owner_id(&walk_state->method_desc->method. | 576 | acpi_ut_release_owner_id(&method_desc->method.owner_id); |
552 | owner_id); | ||
553 | } | 577 | } |
554 | 578 | ||
555 | exit: | 579 | exit: |
@@ -586,7 +610,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | |||
586 | union acpi_parse_object *op; | 610 | union acpi_parse_object *op; |
587 | struct acpi_walk_state *walk_state; | 611 | struct acpi_walk_state *walk_state; |
588 | 612 | ||
589 | ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node); | 613 | ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node); |
590 | 614 | ||
591 | /* Parameter Validation */ | 615 | /* Parameter Validation */ |
592 | 616 | ||
@@ -595,7 +619,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | |||
595 | } | 619 | } |
596 | 620 | ||
597 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | 621 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
598 | "**** Parsing [%4.4s] **** named_obj=%p\n", | 622 | "**** Parsing [%4.4s] **** NamedObj=%p\n", |
599 | acpi_ut_get_node_name(node), node)); | 623 | acpi_ut_get_node_name(node), node)); |
600 | 624 | ||
601 | /* Extract the method object from the method Node */ | 625 | /* Extract the method object from the method Node */ |
@@ -674,7 +698,7 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | |||
674 | } | 698 | } |
675 | 699 | ||
676 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | 700 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, |
677 | "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", | 701 | "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n", |
678 | acpi_ut_get_node_name(node), node, op)); | 702 | acpi_ut_get_node_name(node), node, op)); |
679 | 703 | ||
680 | /* | 704 | /* |