diff options
Diffstat (limited to 'drivers/acpi/dispatcher/dsmethod.c')
-rw-r--r-- | drivers/acpi/dispatcher/dsmethod.c | 337 |
1 files changed, 179 insertions, 158 deletions
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c index 36c1ca0b9adb..58ad00b31ee9 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/dispatcher/dsmethod.c | |||
@@ -53,133 +53,6 @@ ACPI_MODULE_NAME("dsmethod") | |||
53 | 53 | ||
54 | /******************************************************************************* | 54 | /******************************************************************************* |
55 | * | 55 | * |
56 | * FUNCTION: acpi_ds_parse_method | ||
57 | * | ||
58 | * PARAMETERS: Node - Method node | ||
59 | * | ||
60 | * RETURN: Status | ||
61 | * | ||
62 | * DESCRIPTION: Parse the AML that is associated with the method. | ||
63 | * | ||
64 | * MUTEX: Assumes parser is locked | ||
65 | * | ||
66 | ******************************************************************************/ | ||
67 | acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | ||
68 | { | ||
69 | acpi_status status; | ||
70 | union acpi_operand_object *obj_desc; | ||
71 | union acpi_parse_object *op; | ||
72 | struct acpi_walk_state *walk_state; | ||
73 | |||
74 | ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node); | ||
75 | |||
76 | /* Parameter Validation */ | ||
77 | |||
78 | if (!node) { | ||
79 | return_ACPI_STATUS(AE_NULL_ENTRY); | ||
80 | } | ||
81 | |||
82 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
83 | "**** Parsing [%4.4s] **** named_obj=%p\n", | ||
84 | acpi_ut_get_node_name(node), node)); | ||
85 | |||
86 | /* Extract the method object from the method Node */ | ||
87 | |||
88 | obj_desc = acpi_ns_get_attached_object(node); | ||
89 | if (!obj_desc) { | ||
90 | return_ACPI_STATUS(AE_NULL_OBJECT); | ||
91 | } | ||
92 | |||
93 | /* Create a mutex for the method if there is a concurrency limit */ | ||
94 | |||
95 | if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && | ||
96 | (!obj_desc->method.semaphore)) { | ||
97 | status = acpi_os_create_semaphore(obj_desc->method.concurrency, | ||
98 | obj_desc->method.concurrency, | ||
99 | &obj_desc->method.semaphore); | ||
100 | if (ACPI_FAILURE(status)) { | ||
101 | return_ACPI_STATUS(status); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * Allocate a new parser op to be the root of the parsed | ||
107 | * method tree | ||
108 | */ | ||
109 | op = acpi_ps_alloc_op(AML_METHOD_OP); | ||
110 | if (!op) { | ||
111 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
112 | } | ||
113 | |||
114 | /* Init new op with the method name and pointer back to the Node */ | ||
115 | |||
116 | acpi_ps_set_name(op, node->name.integer); | ||
117 | op->common.node = node; | ||
118 | |||
119 | /* | ||
120 | * Get a new owner_id for objects created by this method. Namespace | ||
121 | * objects (such as Operation Regions) can be created during the | ||
122 | * first pass parse. | ||
123 | */ | ||
124 | status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); | ||
125 | if (ACPI_FAILURE(status)) { | ||
126 | goto cleanup; | ||
127 | } | ||
128 | |||
129 | /* Create and initialize a new walk state */ | ||
130 | |||
131 | walk_state = | ||
132 | acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL, | ||
133 | NULL); | ||
134 | if (!walk_state) { | ||
135 | status = AE_NO_MEMORY; | ||
136 | goto cleanup2; | ||
137 | } | ||
138 | |||
139 | status = acpi_ds_init_aml_walk(walk_state, op, node, | ||
140 | obj_desc->method.aml_start, | ||
141 | obj_desc->method.aml_length, NULL, 1); | ||
142 | if (ACPI_FAILURE(status)) { | ||
143 | acpi_ds_delete_walk_state(walk_state); | ||
144 | goto cleanup2; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Parse the method, first pass | ||
149 | * | ||
150 | * The first pass load is where newly declared named objects are added into | ||
151 | * the namespace. Actual evaluation of the named objects (what would be | ||
152 | * called a "second pass") happens during the actual execution of the | ||
153 | * method so that operands to the named objects can take on dynamic | ||
154 | * run-time values. | ||
155 | */ | ||
156 | status = acpi_ps_parse_aml(walk_state); | ||
157 | if (ACPI_FAILURE(status)) { | ||
158 | goto cleanup2; | ||
159 | } | ||
160 | |||
161 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
162 | "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", | ||
163 | acpi_ut_get_node_name(node), node, op)); | ||
164 | |||
165 | /* | ||
166 | * Delete the parse tree. We simply re-parse the method for every | ||
167 | * execution since there isn't much overhead (compared to keeping lots | ||
168 | * of parse trees around) | ||
169 | */ | ||
170 | acpi_ns_delete_namespace_subtree(node); | ||
171 | acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id); | ||
172 | |||
173 | cleanup2: | ||
174 | acpi_ut_release_owner_id(&obj_desc->method.owner_id); | ||
175 | |||
176 | cleanup: | ||
177 | acpi_ps_delete_parse_tree(op); | ||
178 | return_ACPI_STATUS(status); | ||
179 | } | ||
180 | |||
181 | /******************************************************************************* | ||
182 | * | ||
183 | * FUNCTION: acpi_ds_begin_method_execution | 56 | * FUNCTION: acpi_ds_begin_method_execution |
184 | * | 57 | * |
185 | * PARAMETERS: method_node - Node of the method | 58 | * PARAMETERS: method_node - Node of the method |
@@ -193,7 +66,6 @@ acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | |||
193 | * for clearance to execute. | 66 | * for clearance to execute. |
194 | * | 67 | * |
195 | ******************************************************************************/ | 68 | ******************************************************************************/ |
196 | |||
197 | acpi_status | 69 | acpi_status |
198 | acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, | 70 | acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, |
199 | union acpi_operand_object *obj_desc, | 71 | union acpi_operand_object *obj_desc, |
@@ -545,16 +417,54 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | |||
545 | } | 417 | } |
546 | } | 418 | } |
547 | 419 | ||
420 | /* | ||
421 | * There are no more threads executing this method. Perform | ||
422 | * additional cleanup. | ||
423 | * | ||
424 | * The method Node is stored in the walk state | ||
425 | */ | ||
426 | method_node = walk_state->method_node; | ||
427 | |||
428 | /* Lock namespace for possible update */ | ||
429 | |||
430 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | ||
431 | if (ACPI_FAILURE(status)) { | ||
432 | goto exit; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Delete any namespace entries created immediately underneath | ||
437 | * the method | ||
438 | */ | ||
439 | if (method_node->child) { | ||
440 | acpi_ns_delete_namespace_subtree(method_node); | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * Delete any namespace entries created anywhere else within | ||
445 | * the namespace by the execution of this method | ||
446 | */ | ||
447 | acpi_ns_delete_namespace_by_owner(walk_state->method_desc->method. | ||
448 | owner_id); | ||
449 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
450 | |||
451 | /* Are there any other threads currently executing this method? */ | ||
452 | |||
548 | if (walk_state->method_desc->method.thread_count) { | 453 | if (walk_state->method_desc->method.thread_count) { |
454 | /* | ||
455 | * Additional threads. Do not release the owner_id in this case, | ||
456 | * we immediately reuse it for the next thread executing this method | ||
457 | */ | ||
549 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, | 458 | ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, |
550 | "*** Not deleting method namespace, there are still %d threads\n", | 459 | "*** Completed execution of one thread, %d threads remaining\n", |
551 | walk_state->method_desc->method. | 460 | walk_state->method_desc->method. |
552 | thread_count)); | 461 | thread_count)); |
553 | } else { /* This is the last executing thread */ | 462 | } else { |
463 | /* This is the only executing thread for this method */ | ||
554 | 464 | ||
555 | /* | 465 | /* |
556 | * Support to dynamically change a method from not_serialized to | 466 | * Support to dynamically change a method from not_serialized to |
557 | * Serialized if it appears that the method is written foolishly and | 467 | * Serialized if it appears that the method is incorrectly written and |
558 | * does not support multiple thread execution. The best example of this | 468 | * does not support multiple thread execution. The best example of this |
559 | * is if such a method creates namespace objects and blocks. A second | 469 | * is if such a method creates namespace objects and blocks. A second |
560 | * thread will fail with an AE_ALREADY_EXISTS exception | 470 | * thread will fail with an AE_ALREADY_EXISTS exception |
@@ -570,34 +480,8 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | |||
570 | semaphore); | 480 | semaphore); |
571 | } | 481 | } |
572 | 482 | ||
573 | /* | 483 | /* No more threads, we can free the owner_id */ |
574 | * There are no more threads executing this method. Perform | ||
575 | * additional cleanup. | ||
576 | * | ||
577 | * The method Node is stored in the walk state | ||
578 | */ | ||
579 | method_node = walk_state->method_node; | ||
580 | |||
581 | /* | ||
582 | * Delete any namespace entries created immediately underneath | ||
583 | * the method | ||
584 | */ | ||
585 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | ||
586 | if (ACPI_FAILURE(status)) { | ||
587 | goto exit; | ||
588 | } | ||
589 | |||
590 | if (method_node->child) { | ||
591 | acpi_ns_delete_namespace_subtree(method_node); | ||
592 | } | ||
593 | 484 | ||
594 | /* | ||
595 | * Delete any namespace entries created anywhere else within | ||
596 | * the namespace | ||
597 | */ | ||
598 | acpi_ns_delete_namespace_by_owner(walk_state->method_desc-> | ||
599 | method.owner_id); | ||
600 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
601 | acpi_ut_release_owner_id(&walk_state->method_desc->method. | 485 | acpi_ut_release_owner_id(&walk_state->method_desc->method. |
602 | owner_id); | 486 | owner_id); |
603 | } | 487 | } |
@@ -606,3 +490,140 @@ void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) | |||
606 | (void)acpi_ut_release_mutex(ACPI_MTX_PARSER); | 490 | (void)acpi_ut_release_mutex(ACPI_MTX_PARSER); |
607 | return_VOID; | 491 | return_VOID; |
608 | } | 492 | } |
493 | |||
494 | #ifdef ACPI_INIT_PARSE_METHODS | ||
495 | /* | ||
496 | * Note 11/2005: Removed this code to parse all methods during table | ||
497 | * load because it causes problems if there are any errors during the | ||
498 | * parse. Also, it seems like overkill and we probably don't want to | ||
499 | * abort a table load because of an issue with a single method. | ||
500 | */ | ||
501 | |||
502 | /******************************************************************************* | ||
503 | * | ||
504 | * FUNCTION: acpi_ds_parse_method | ||
505 | * | ||
506 | * PARAMETERS: Node - Method node | ||
507 | * | ||
508 | * RETURN: Status | ||
509 | * | ||
510 | * DESCRIPTION: Parse the AML that is associated with the method. | ||
511 | * | ||
512 | * MUTEX: Assumes parser is locked | ||
513 | * | ||
514 | ******************************************************************************/ | ||
515 | |||
516 | acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node) | ||
517 | { | ||
518 | acpi_status status; | ||
519 | union acpi_operand_object *obj_desc; | ||
520 | union acpi_parse_object *op; | ||
521 | struct acpi_walk_state *walk_state; | ||
522 | |||
523 | ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node); | ||
524 | |||
525 | /* Parameter Validation */ | ||
526 | |||
527 | if (!node) { | ||
528 | return_ACPI_STATUS(AE_NULL_ENTRY); | ||
529 | } | ||
530 | |||
531 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
532 | "**** Parsing [%4.4s] **** named_obj=%p\n", | ||
533 | acpi_ut_get_node_name(node), node)); | ||
534 | |||
535 | /* Extract the method object from the method Node */ | ||
536 | |||
537 | obj_desc = acpi_ns_get_attached_object(node); | ||
538 | if (!obj_desc) { | ||
539 | return_ACPI_STATUS(AE_NULL_OBJECT); | ||
540 | } | ||
541 | |||
542 | /* Create a mutex for the method if there is a concurrency limit */ | ||
543 | |||
544 | if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) && | ||
545 | (!obj_desc->method.semaphore)) { | ||
546 | status = acpi_os_create_semaphore(obj_desc->method.concurrency, | ||
547 | obj_desc->method.concurrency, | ||
548 | &obj_desc->method.semaphore); | ||
549 | if (ACPI_FAILURE(status)) { | ||
550 | return_ACPI_STATUS(status); | ||
551 | } | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * Allocate a new parser op to be the root of the parsed | ||
556 | * method tree | ||
557 | */ | ||
558 | op = acpi_ps_alloc_op(AML_METHOD_OP); | ||
559 | if (!op) { | ||
560 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
561 | } | ||
562 | |||
563 | /* Init new op with the method name and pointer back to the Node */ | ||
564 | |||
565 | acpi_ps_set_name(op, node->name.integer); | ||
566 | op->common.node = node; | ||
567 | |||
568 | /* | ||
569 | * Get a new owner_id for objects created by this method. Namespace | ||
570 | * objects (such as Operation Regions) can be created during the | ||
571 | * first pass parse. | ||
572 | */ | ||
573 | status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id); | ||
574 | if (ACPI_FAILURE(status)) { | ||
575 | goto cleanup; | ||
576 | } | ||
577 | |||
578 | /* Create and initialize a new walk state */ | ||
579 | |||
580 | walk_state = | ||
581 | acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL, | ||
582 | NULL); | ||
583 | if (!walk_state) { | ||
584 | status = AE_NO_MEMORY; | ||
585 | goto cleanup2; | ||
586 | } | ||
587 | |||
588 | status = acpi_ds_init_aml_walk(walk_state, op, node, | ||
589 | obj_desc->method.aml_start, | ||
590 | obj_desc->method.aml_length, NULL, 1); | ||
591 | if (ACPI_FAILURE(status)) { | ||
592 | acpi_ds_delete_walk_state(walk_state); | ||
593 | goto cleanup2; | ||
594 | } | ||
595 | |||
596 | /* | ||
597 | * Parse the method, first pass | ||
598 | * | ||
599 | * The first pass load is where newly declared named objects are added into | ||
600 | * the namespace. Actual evaluation of the named objects (what would be | ||
601 | * called a "second pass") happens during the actual execution of the | ||
602 | * method so that operands to the named objects can take on dynamic | ||
603 | * run-time values. | ||
604 | */ | ||
605 | status = acpi_ps_parse_aml(walk_state); | ||
606 | if (ACPI_FAILURE(status)) { | ||
607 | goto cleanup2; | ||
608 | } | ||
609 | |||
610 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
611 | "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", | ||
612 | acpi_ut_get_node_name(node), node, op)); | ||
613 | |||
614 | /* | ||
615 | * Delete the parse tree. We simply re-parse the method for every | ||
616 | * execution since there isn't much overhead (compared to keeping lots | ||
617 | * of parse trees around) | ||
618 | */ | ||
619 | acpi_ns_delete_namespace_subtree(node); | ||
620 | acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id); | ||
621 | |||
622 | cleanup2: | ||
623 | acpi_ut_release_owner_id(&obj_desc->method.owner_id); | ||
624 | |||
625 | cleanup: | ||
626 | acpi_ps_delete_parse_tree(op); | ||
627 | return_ACPI_STATUS(status); | ||
628 | } | ||
629 | #endif | ||