acpi_status acpi_tb_release_owner_id(u32 table_index) { acpi_status status = AE_BAD_PARAMETER; ACPI_FUNCTION_TRACE(tb_release_owner_id); (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); if (table_index < acpi_gbl_root_table_list.current_table_count) { acpi_ut_release_owner_id(& (acpi_gbl_root_table_list. tables[table_index].owner_id)); status = AE_OK; } (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); }
struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) { struct acpi_table_desc *next_desc; ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc); if (!table_desc) { return_PTR(NULL); } /* Unlink the descriptor from the doubly linked list */ if (table_desc->prev) { table_desc->prev->next = table_desc->next; } else { /* Is first on list, update list head */ acpi_gbl_table_lists[table_desc->type].next = table_desc->next; } if (table_desc->next) { table_desc->next->prev = table_desc->prev; } /* Free the memory allocated for the table itself */ acpi_tb_delete_single_table(table_desc); /* Free the owner ID associated with this table */ acpi_ut_release_owner_id(&table_desc->owner_id); /* Free the table descriptor */ next_desc = table_desc->next; ACPI_FREE(table_desc); /* Return pointer to the next descriptor */ return_PTR(next_desc); }
acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) { acpi_status status = AE_OK; union acpi_operand_object *table_desc = ddb_handle; struct acpi_table_desc *table_info; ACPI_FUNCTION_TRACE("ex_unload_table"); /* * Validate the handle * Although the handle is partially validated in acpi_ex_reconfiguration(), * when it calls acpi_ex_resolve_operands(), the handle is more completely * validated here. */ if ((!ddb_handle) || (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || (ACPI_GET_OBJECT_TYPE(ddb_handle) != ACPI_TYPE_LOCAL_REFERENCE)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Get the actual table descriptor from the ddb_handle */ table_info = (struct acpi_table_desc *)table_desc->reference.object; /* * Delete the entire namespace under this table Node * (Offset contains the table_id) */ acpi_ns_delete_namespace_by_owner(table_info->owner_id); acpi_ut_release_owner_id(&table_info->owner_id); /* Delete the table itself */ (void)acpi_tb_uninstall_table(table_info->installed_desc); /* Delete the table descriptor (ddb_handle) */ acpi_ut_remove_reference(table_desc); return_ACPI_STATUS(status); }
void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { struct acpi_namespace_node *method_node; acpi_status status; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); /* method_desc is required, walk_state is optional */ if (!method_desc) { return_VOID; } if (walk_state) { /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); } /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (method_desc->method.mutex) { /* Acquisition Depth handles recursive calls */ 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; acpi_os_release_mutex(method_desc->method.mutex->mutex. os_mutex); method_desc->method.mutex->mutex.owner_thread_id = ACPI_MUTEX_NOT_ACQUIRED; } } 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; /* * Delete any namespace objects created anywhere within * the namespace by the execution of this method */ acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id); } /* 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")); } /* Are there any other threads currently executing this method? */ if (method_desc->method.thread_count) { /* * Additional threads. Do not release the owner_id in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %d threads remaining\n", method_desc->method.thread_count)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from not_serialized to * Serialized if it appears that the method is incorrectly written and * 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. */ if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED) && (!method_desc->method.mutex)) { status = acpi_ds_create_method_mutex(method_desc); } /* No more threads, we can free the owner_id */ acpi_ut_release_owner_id(&method_desc->method.owner_id); } return_VOID; }
/******************************************************************************* * * 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; ACPI_FUNCTION_TRACE_PTR("ds_parse_method", node); /* Parameter Validation */ if (!node) { return_ACPI_STATUS(AE_NULL_ENTRY); } ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n", 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, "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n", 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); }
void acpi_ds_terminate_control_method(struct acpi_walk_state *walk_state) { union acpi_operand_object *obj_desc; struct acpi_namespace_node *method_node; acpi_status status; ACPI_FUNCTION_TRACE_PTR("ds_terminate_control_method", walk_state); if (!walk_state) { return_VOID; } /* The current method object was saved in the walk state */ obj_desc = walk_state->method_desc; if (!obj_desc) { return_VOID; } /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); /* * Lock the parser while we terminate this method. * If this is the last thread executing the method, * we have additional cleanup to perform */ status = acpi_ut_acquire_mutex(ACPI_MTX_PARSER); if (ACPI_FAILURE(status)) { return_VOID; } /* Signal completion of the execution of this method if necessary */ if (walk_state->method_desc->method.semaphore) { status = acpi_os_signal_semaphore(walk_state->method_desc->method. semaphore, 1); if (ACPI_FAILURE(status)) { ACPI_REPORT_ERROR(("Could not signal method semaphore\n")); /* Ignore error and continue cleanup */ } } if (walk_state->method_desc->method.thread_count) { ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Not deleting method namespace, there are still %d threads\n", walk_state->method_desc->method. thread_count)); } else { /* This is the last executing thread */ /* * Support to dynamically change a method from not_serialized to * Serialized if it appears that the method is written foolishly and * 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. */ if ((walk_state->method_desc->method.concurrency == 1) && (!walk_state->method_desc->method.semaphore)) { status = acpi_os_create_semaphore(1, 1, &walk_state-> method_desc->method. semaphore); } /* * There are no more threads executing this method. Perform * additional cleanup. * * The method Node is stored in the walk state */ method_node = walk_state->method_node; /* * Delete any namespace entries created immediately underneath * the method */ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); if (ACPI_FAILURE(status)) { goto exit; } if (method_node->child) { acpi_ns_delete_namespace_subtree(method_node); } /* * Delete any namespace entries created anywhere else within * the namespace */ acpi_ns_delete_namespace_by_owner(walk_state->method_desc-> method.owner_id); status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); acpi_ut_release_owner_id(&walk_state->method_desc->method. owner_id); } exit: (void)acpi_ut_release_mutex(ACPI_MTX_PARSER); return_VOID; }
void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); /* method_desc is required, walk_state is optional */ if (!method_desc) { return_VOID; } if (walk_state) { /* Delete all arguments and locals */ acpi_ds_method_data_delete_all(walk_state); /* * If method is serialized, release the mutex and restore the * current sync level for this thread */ if (method_desc->method.mutex) { /* Acquisition Depth handles recursive calls */ 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; acpi_os_release_mutex(method_desc->method. mutex->mutex.os_mutex); method_desc->method.mutex->mutex.thread_id = 0; } } /* * Delete any namespace objects created anywhere within the * namespace by the execution of this method. Unless: * 1) This method is a module-level executable code method, in which * case we want make the objects permanent. * 2) There are other threads executing the method, in which case we * will wait until the last thread has completed. */ if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) && (method_desc->method.thread_count == 1)) { /* Delete any direct children of (created by) this method */ acpi_ns_delete_namespace_subtree(walk_state-> method_node); /* * Delete any objects that were created by this method * elsewhere in the namespace (if any were created). * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the * deletion such that we don't have to perform an entire * namespace walk for every control method execution. */ if (method_desc->method. info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) { acpi_ns_delete_namespace_by_owner(method_desc-> method. owner_id); method_desc->method.info_flags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; } } } /* 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")); } /* Are there any other threads currently executing this method? */ if (method_desc->method.thread_count) { /* * Additional threads. Do not release the owner_id in this case, * we immediately reuse it for the next thread executing this method */ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "*** Completed execution of one thread, %u threads remaining\n", method_desc->method.thread_count)); } else { /* This is the only executing thread for this method */ /* * Support to dynamically change a method from not_serialized to * Serialized if it appears that the method is incorrectly written and * 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 marking the method as serialized. */ if (method_desc->method. info_flags & ACPI_METHOD_SERIALIZED_PENDING) { if (walk_state) { ACPI_INFO((AE_INFO, "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", walk_state->method_node->name. ascii)); } /* * Method tried to create an object twice and was marked as * "pending serialized". The probable cause is that the method * cannot handle reentrancy. * * The method was created as not_serialized, but it tried to create * a named object and then blocked, causing the second thread * entrance to begin and then fail. Workaround this problem by * marking the method permanently as Serialized when the last * thread exits here. */ method_desc->method.info_flags &= ~ACPI_METHOD_SERIALIZED_PENDING; method_desc->method.info_flags |= (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); method_desc->method.sync_level = 0; } /* No more threads, we can free the owner_id */ if (! (method_desc->method. info_flags & ACPI_METHOD_MODULE_LEVEL)) { acpi_ut_release_owner_id(&method_desc->method.owner_id); } } return_VOID; }
/**ltl * 功能:将ACPI表的描述符信息插入到全局列表中 * 参数: * 返回值: * 说明:表类型table_type分别为:0(RSDP)、6 (XSDT)、2 (FADT)、5 (SSDT)、5 (SSDT)、3 (FACS)、1 (DSDT) */ acpi_status acpi_tb_init_table_descriptor(acpi_table_type table_type, struct acpi_table_desc *table_info) { struct acpi_table_list *list_head; struct acpi_table_desc *table_desc; acpi_status status; ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type); /* Allocate a descriptor for this table */ /* 分配ACPI表描述符信息 */ table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc)); if (!table_desc) { return_ACPI_STATUS(AE_NO_MEMORY); } /* Get a new owner ID for the table */ /* 为ACPI表描述符分配ID */ status = acpi_ut_allocate_owner_id(&table_desc->owner_id); if (ACPI_FAILURE(status)) { goto error_exit1; } /* Install the table into the global data structure */ /* 全局列表 */ list_head = &acpi_gbl_table_lists[table_type]; /* * Two major types of tables: 1) Only one instance is allowed. This * includes most ACPI tables such as the DSDT. 2) Multiple instances of * the table are allowed. This includes SSDT and PSDTs. */ /* 如果此ACPI表在系统中只能是唯一一个 */ if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) { /* * Only one table allowed, and a table has alread been installed * at this location, so return an error. */ if (list_head->next) { /* 表示此表已经存在,退出 */ status = AE_ALREADY_EXISTS; goto error_exit2; } /* 将ACPI表描述符对象插入到全局列表中 */ table_desc->next = list_head->next; list_head->next = table_desc; if (table_desc->next) { table_desc->next->prev = table_desc; } list_head->count++; } else { /* * Link the new table in to the list of tables of this type. * Insert at the end of the list, order IS IMPORTANT. * * table_desc->Prev & Next are already NULL from calloc() */ /* 在系统中引出现多张相同的ACPI表,把它们以链表的形式链接 */ list_head->count++; if (!list_head->next) { list_head->next = table_desc; } else { table_desc->next = list_head->next; while (table_desc->next->next) { table_desc->next = table_desc->next->next; } table_desc->next->next = table_desc; table_desc->prev = table_desc->next; table_desc->next = NULL; } } /* Finish initialization of the table descriptor */ table_desc->loaded_into_namespace = FALSE; table_desc->type = (u8) table_type; table_desc->pointer = table_info->pointer; table_desc->length = table_info->length; table_desc->allocation = table_info->allocation; table_desc->aml_start = (u8 *) (table_desc->pointer + 1), table_desc->aml_length = (u32) (table_desc->length - (u32) sizeof(struct acpi_table_header)); /* * Set the appropriate global pointer (if there is one) to point to the * newly installed table */ /* 将ACPI表的起始地址保存到global_ptr中。在这语句是对全局变量:acpi_gbl_FADT、acpi_gbl_FACS、acpi_gbl_DSDT * 进行赋值 */ if (acpi_gbl_table_data[table_type].global_ptr) { *(acpi_gbl_table_data[table_type].global_ptr) = table_info->pointer; } /* Return Data */ table_info->owner_id = table_desc->owner_id; table_info->installed_desc = table_desc; return_ACPI_STATUS(AE_OK); /* Error exit with cleanup */ error_exit2: acpi_ut_release_owner_id(&table_desc->owner_id); error_exit1: ACPI_FREE(table_desc); return_ACPI_STATUS(status); }