Commit ac0f06eb authored by Lv Zheng's avatar Lv Zheng Committed by Rafael J. Wysocki

ACPICA: Tables: Tune table mutex to be a leaf lock

ACPICA commit f564d57c6501b97a2871f0b4c048e79910f71783

This patch tunes MTX_TABLES into a leaf lock by always ensuring it is
released before holding other locks.

This patch also collects all table loading related functions into
acpi_tb_load_table() (invoked by load_table opcode) and
acpi_tb_install_and_load_table() (invoked by Load opcode and acpi_load_table()) so
that we can have lock tuning code collected at the boundary of these 2
functions. Lv Zheng.

Link: https://github.com/acpica/acpica/commit/f564d57cTested-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Tested-by: default avatarDutch Guy <lucht_piloot@gmx.net>
Signed-off-by: default avatarLv Zheng <lv.zheng@intel.com>
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 441ad11d
...@@ -123,6 +123,14 @@ acpi_tb_install_standard_table(acpi_physical_address address, ...@@ -123,6 +123,14 @@ acpi_tb_install_standard_table(acpi_physical_address address,
void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc); void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc);
acpi_status
acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node);
acpi_status
acpi_tb_install_and_load_table(struct acpi_table_header *table,
acpi_physical_address address,
u8 flags, u8 override, u32 *table_index);
void acpi_tb_terminate(void); void acpi_tb_terminate(void);
acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index); acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index);
......
...@@ -55,9 +55,7 @@ ACPI_MODULE_NAME("exconfig") ...@@ -55,9 +55,7 @@ ACPI_MODULE_NAME("exconfig")
/* Local prototypes */ /* Local prototypes */
static acpi_status static acpi_status
acpi_ex_add_table(u32 table_index, acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle);
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle);
static acpi_status static acpi_status
acpi_ex_region_read(union acpi_operand_object *obj_desc, acpi_ex_region_read(union acpi_operand_object *obj_desc,
...@@ -79,13 +77,9 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, ...@@ -79,13 +77,9 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc,
******************************************************************************/ ******************************************************************************/
static acpi_status static acpi_status
acpi_ex_add_table(u32 table_index, acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle)
struct acpi_namespace_node *parent_node,
union acpi_operand_object **ddb_handle)
{ {
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
acpi_status status;
acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(ex_add_table); ACPI_FUNCTION_TRACE(ex_add_table);
...@@ -100,40 +94,8 @@ acpi_ex_add_table(u32 table_index, ...@@ -100,40 +94,8 @@ acpi_ex_add_table(u32 table_index,
obj_desc->common.flags |= AOPOBJ_DATA_VALID; obj_desc->common.flags |= AOPOBJ_DATA_VALID;
obj_desc->reference.class = ACPI_REFCLASS_TABLE; obj_desc->reference.class = ACPI_REFCLASS_TABLE;
*ddb_handle = obj_desc;
/* Install the new table into the local data structures */
obj_desc->reference.value = table_index; obj_desc->reference.value = table_index;
*ddb_handle = obj_desc;
/* Add the table to the namespace */
status = acpi_ns_load_table(table_index, parent_node);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(obj_desc);
*ddb_handle = NULL;
return_ACPI_STATUS(status);
}
/* Execute any module-level code that was found in the table */
acpi_ex_exit_interpreter();
if (!acpi_gbl_parse_table_as_term_list
&& acpi_gbl_group_module_level_code) {
acpi_ns_exec_module_code_list();
}
acpi_ex_enter_interpreter();
/*
* Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
* responsible for discovering any new wake GPEs by running _PRW methods
* that may have been loaded by this table.
*/
status = acpi_tb_get_owner_id(table_index, &owner_id);
if (ACPI_SUCCESS(status)) {
acpi_ev_update_gpes(owner_id);
}
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }
...@@ -160,16 +122,17 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, ...@@ -160,16 +122,17 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
struct acpi_namespace_node *start_node; struct acpi_namespace_node *start_node;
struct acpi_namespace_node *parameter_node = NULL; struct acpi_namespace_node *parameter_node = NULL;
union acpi_operand_object *ddb_handle; union acpi_operand_object *ddb_handle;
struct acpi_table_header *table;
u32 table_index; u32 table_index;
ACPI_FUNCTION_TRACE(ex_load_table_op); ACPI_FUNCTION_TRACE(ex_load_table_op);
/* Find the ACPI table in the RSDT/XSDT */ /* Find the ACPI table in the RSDT/XSDT */
acpi_ex_exit_interpreter();
status = acpi_tb_find_table(operand[0]->string.pointer, status = acpi_tb_find_table(operand[0]->string.pointer,
operand[1]->string.pointer, operand[1]->string.pointer,
operand[2]->string.pointer, &table_index); operand[2]->string.pointer, &table_index);
acpi_ex_enter_interpreter();
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND) { if (status != AE_NOT_FOUND) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
...@@ -232,7 +195,15 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, ...@@ -232,7 +195,15 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
/* Load the table into the namespace */ /* Load the table into the namespace */
status = acpi_ex_add_table(table_index, parent_node, &ddb_handle); ACPI_INFO(("Dynamic OEM Table Load:"));
acpi_ex_exit_interpreter();
status = acpi_tb_load_table(table_index, parent_node);
acpi_ex_enter_interpreter();
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status = acpi_ex_add_table(table_index, &ddb_handle);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
...@@ -255,19 +226,6 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, ...@@ -255,19 +226,6 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
} }
} }
status = acpi_get_table_by_index(table_index, &table);
if (ACPI_SUCCESS(status)) {
ACPI_INFO(("Dynamic OEM Table Load:"));
acpi_tb_print_table_header(0, table);
}
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
*return_desc = ddb_handle; *return_desc = ddb_handle;
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
...@@ -478,13 +436,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ...@@ -478,13 +436,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Install the new table into the local data structures */ /* Install the new table into the local data structures */
ACPI_INFO(("Dynamic OEM Table Load:")); ACPI_INFO(("Dynamic OEM Table Load:"));
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); acpi_ex_exit_interpreter();
status =
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table), acpi_tb_install_and_load_table(table, ACPI_PTR_TO_PHYSADDR(table),
ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
TRUE, TRUE, &table_index); TRUE, &table_index);
acpi_ex_enter_interpreter();
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* Delete allocated table buffer */ /* Delete allocated table buffer */
...@@ -493,17 +450,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ...@@ -493,17 +450,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
/*
* Note: Now table is "INSTALLED", it must be validated before
* loading.
*/
status =
acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[table_index]);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* /*
* Add the table to the namespace. * Add the table to the namespace.
* *
...@@ -511,8 +457,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ...@@ -511,8 +457,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
* This appears to go against the ACPI specification, but we do it for * This appears to go against the ACPI specification, but we do it for
* compatibility with other ACPI implementations. * compatibility with other ACPI implementations.
*/ */
status = status = acpi_ex_add_table(table_index, &ddb_handle);
acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */ /* On error, table_ptr was deallocated above */
...@@ -535,14 +480,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, ...@@ -535,14 +480,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Remove the reference by added by acpi_ex_store above */ /* Remove the reference by added by acpi_ex_store above */
acpi_ut_remove_reference(ddb_handle); acpi_ut_remove_reference(ddb_handle);
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "accommon.h" #include "accommon.h"
#include "acnamesp.h" #include "acnamesp.h"
#include "actables.h" #include "actables.h"
#include "acevents.h"
#define _COMPONENT ACPI_TABLES #define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbdata") ACPI_MODULE_NAME("tbdata")
...@@ -771,3 +772,142 @@ void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded) ...@@ -771,3 +772,142 @@ void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
} }
/*******************************************************************************
*
* FUNCTION: acpi_tb_load_table
*
* PARAMETERS: table_index - Table index
* parent_node - Where table index is returned
*
* RETURN: Status
*
* DESCRIPTION: Load an ACPI table
*
******************************************************************************/
acpi_status
acpi_tb_load_table(u32 table_index, struct acpi_namespace_node *parent_node)
{
struct acpi_table_header *table;
acpi_status status;
acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(tb_load_table);
/*
* Note: Now table is "INSTALLED", it must be validated before
* using.
*/
status = acpi_get_table_by_index(table_index, &table);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status = acpi_ns_load_table(table_index, parent_node);
/* Execute any module-level code that was found in the table */
if (!acpi_gbl_parse_table_as_term_list
&& acpi_gbl_group_module_level_code) {
acpi_ns_exec_module_code_list();
}
/*
* Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
* responsible for discovering any new wake GPEs by running _PRW methods
* that may have been loaded by this table.
*/
status = acpi_tb_get_owner_id(table_index, &owner_id);
if (ACPI_SUCCESS(status)) {
acpi_ev_update_gpes(owner_id);
}
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
return_ACPI_STATUS(status);
}
/*******************************************************************************
*
* FUNCTION: acpi_tb_install_and_load_table
*
* PARAMETERS: table - Pointer to the table
* address - Physical address of the table
* flags - Allocation flags of the table
* table_index - Where table index is returned
*
* RETURN: Status
*
* DESCRIPTION: Install and load an ACPI table
*
******************************************************************************/
acpi_status
acpi_tb_install_and_load_table(struct acpi_table_header *table,
acpi_physical_address address,
u8 flags, u8 override, u32 *table_index)
{
acpi_status status;
u32 i;
acpi_owner_id owner_id;
ACPI_FUNCTION_TRACE(acpi_load_table);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
/* Install the table and load it into the namespace */
status = acpi_tb_install_standard_table(address, flags, TRUE,
override, &i);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
/*
* Note: Now table is "INSTALLED", it must be validated before
* using.
*/
status = acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
status = acpi_ns_load_table(i, acpi_gbl_root_node);
/* Execute any module-level code that was found in the table */
if (!acpi_gbl_parse_table_as_term_list
&& acpi_gbl_group_module_level_code) {
acpi_ns_exec_module_code_list();
}
/*
* Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
* responsible for discovering any new wake GPEs by running _PRW methods
* that may have been loaded by this table.
*/
status = acpi_tb_get_owner_id(i, &owner_id);
if (ACPI_SUCCESS(status)) {
acpi_ev_update_gpes(owner_id);
}
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
unlock_and_exit:
*table_index = i;
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
...@@ -68,7 +68,7 @@ acpi_status ...@@ -68,7 +68,7 @@ acpi_status
acpi_tb_find_table(char *signature, acpi_tb_find_table(char *signature,
char *oem_id, char *oem_table_id, u32 *table_index) char *oem_id, char *oem_table_id, u32 *table_index)
{ {
acpi_status status; acpi_status status = AE_OK;
struct acpi_table_header header; struct acpi_table_header header;
u32 i; u32 i;
...@@ -96,6 +96,7 @@ acpi_tb_find_table(char *signature, ...@@ -96,6 +96,7 @@ acpi_tb_find_table(char *signature,
/* Search for the table */ /* Search for the table */
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
if (memcmp(&(acpi_gbl_root_table_list.tables[i].signature), if (memcmp(&(acpi_gbl_root_table_list.tables[i].signature),
header.signature, ACPI_NAME_SIZE)) { header.signature, ACPI_NAME_SIZE)) {
...@@ -115,7 +116,7 @@ acpi_tb_find_table(char *signature, ...@@ -115,7 +116,7 @@ acpi_tb_find_table(char *signature,
acpi_tb_validate_table(&acpi_gbl_root_table_list. acpi_tb_validate_table(&acpi_gbl_root_table_list.
tables[i]); tables[i]);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); goto unlock_and_exit;
} }
if (!acpi_gbl_root_table_list.tables[i].pointer) { if (!acpi_gbl_root_table_list.tables[i].pointer) {
...@@ -144,9 +145,12 @@ acpi_tb_find_table(char *signature, ...@@ -144,9 +145,12 @@ acpi_tb_find_table(char *signature,
ACPI_DEBUG_PRINT((ACPI_DB_TABLES, ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
"Found table [%4.4s]\n", "Found table [%4.4s]\n",
header.signature)); header.signature));
return_ACPI_STATUS(AE_OK); goto unlock_and_exit;
} }
} }
status = AE_NOT_FOUND;
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(AE_NOT_FOUND); return_ACPI_STATUS(AE_NOT_FOUND);
} }
...@@ -189,11 +189,11 @@ acpi_status acpi_tb_load_namespace(void) ...@@ -189,11 +189,11 @@ acpi_status acpi_tb_load_namespace(void)
memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT, memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT,
sizeof(struct acpi_table_header)); sizeof(struct acpi_table_header));
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
/* Load and parse tables */ /* Load and parse tables */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node); status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed")); ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed"));
tables_failed++; tables_failed++;
...@@ -203,7 +203,6 @@ acpi_status acpi_tb_load_namespace(void) ...@@ -203,7 +203,6 @@ acpi_status acpi_tb_load_namespace(void)
/* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
table = &acpi_gbl_root_table_list.tables[i]; table = &acpi_gbl_root_table_list.tables[i];
...@@ -221,6 +220,7 @@ acpi_status acpi_tb_load_namespace(void) ...@@ -221,6 +220,7 @@ acpi_status acpi_tb_load_namespace(void)
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES); (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
status = acpi_ns_load_table(i, acpi_gbl_root_node); status = acpi_ns_load_table(i, acpi_gbl_root_node);
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status, ACPI_EXCEPTION((AE_INFO, status,
"(%4.4s:%8.8s) while loading table", "(%4.4s:%8.8s) while loading table",
...@@ -236,8 +236,6 @@ acpi_status acpi_tb_load_namespace(void) ...@@ -236,8 +236,6 @@ acpi_status acpi_tb_load_namespace(void)
} else { } else {
tables_loaded++; tables_loaded++;
} }
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
} }
if (!tables_failed) { if (!tables_failed) {
...@@ -325,49 +323,13 @@ acpi_status acpi_load_table(struct acpi_table_header *table) ...@@ -325,49 +323,13 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
} }
/* Must acquire the interpreter lock during this operation */
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
/* Install the table and load it into the namespace */ /* Install the table and load it into the namespace */
ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); ACPI_INFO(("Host-directed Dynamic ACPI Table Load:"));
(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
TRUE, FALSE, &table_index);
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
/*
* Note: Now table is "INSTALLED", it must be validated before
* using.
*/
status = status =
acpi_tb_validate_table(&acpi_gbl_root_table_list. acpi_tb_install_and_load_table(table, ACPI_PTR_TO_PHYSADDR(table),
tables[table_index]); ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
if (ACPI_FAILURE(status)) { FALSE, &table_index);
goto unlock_and_exit;
}
status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment