aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/dispatcher/dsmethod.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2005-12-02 18:27:00 -0500
committerLen Brown <len.brown@intel.com>2005-12-10 00:29:11 -0500
commit28f55ebce5bd2fceec8adc7c8860953d3e4532a8 (patch)
tree2c5c10c18e51f9a717514dfccdc287fc517730c6 /drivers/acpi/dispatcher/dsmethod.c
parentc51a4de85de720670f2fbc592a6f8040af72ad87 (diff)
[ACPI] ACPICA 20051202
Modified the parsing of control methods to no longer create namespace objects during the first pass of the parse. Objects are now created only during the execute phase, at the moment the namespace creation operator is encountered in the AML (Name, OperationRegion, CreateByteField, etc.) This should eliminate ALREADY_EXISTS exceptions seen on some machines where reentrant control methods are protected by an AML mutex. The mutex will now correctly block multiple threads from attempting to create the same object more than once. Increased the number of available Owner Ids for namespace object tracking from 32 to 255. This should eliminate the OWNER_ID_LIMIT exceptions seen on some machines with a large number of ACPI tables (either static or dynamic). Enhanced the namespace dump routine to output the owner ID for each namespace object. Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/dispatcher/dsmethod.c')
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c337
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 ******************************************************************************/
67acpi_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
197acpi_status 69acpi_status
198acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, 70acpi_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
516acpi_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