Enhance acpi_load_table to also return the table index. Use that index to unload the table again when the corresponding directory in configfs gets removed. This allows to change SSDTs without rebooting the system. It also allows to destroy devices again that a dynamically loaded SSDT created. This is widely similar to the DT overlay behavior. Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx> --- Can someone explain to me why an unloaded table still sticks around in sysfs and why we cannot release its ID and rather have to use a new one when loading a modified version? drivers/acpi/acpi_configfs.c | 12 +++++++++++- drivers/acpi/acpica/dbfileio.c | 2 +- drivers/acpi/acpica/tbxfload.c | 38 +++++++++++++++++++++++++++++++++++--- drivers/firmware/efi/efi.c | 2 +- drivers/pci/hotplug/sgi_hotplug.c | 2 +- include/acpi/acpixf.h | 6 +++++- 6 files changed, 54 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpi_configfs.c b/drivers/acpi/acpi_configfs.c index 146a77fb762d..dac8dbf16cc0 100644 --- a/drivers/acpi/acpi_configfs.c +++ b/drivers/acpi/acpi_configfs.c @@ -20,6 +20,7 @@ static struct config_group *acpi_table_group; struct acpi_table { struct config_item cfg; struct acpi_table_header *header; + u32 index; }; static ssize_t acpi_table_aml_write(struct config_item *cfg, @@ -52,7 +53,7 @@ static ssize_t acpi_table_aml_write(struct config_item *cfg, if (!table->header) return -ENOMEM; - ret = acpi_load_table(table->header); + ret = acpi_load_table(table->header, &table->index); if (ret) { kfree(table->header); table->header = NULL; @@ -215,8 +216,17 @@ static struct config_item *acpi_table_make_item(struct config_group *group, return &table->cfg; } +static void acpi_table_drop_item(struct config_group *group, + struct config_item *cfg) +{ + struct acpi_table *table = container_of(cfg, struct acpi_table, cfg); + + acpi_unload_table(table->index); +} + struct configfs_group_operations acpi_table_group_ops = { .make_item = acpi_table_make_item, + .drop_item = acpi_table_drop_item, }; static struct config_item_type acpi_tables_type = { diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c index 4d81ea291d93..4486ec8b995b 100644 --- a/drivers/acpi/acpica/dbfileio.c +++ b/drivers/acpi/acpica/dbfileio.c @@ -129,7 +129,7 @@ acpi_status acpi_db_load_tables(struct acpi_new_table_desc *list_head) while (table_list_head) { table = table_list_head->table; - status = acpi_load_table(table); + status = acpi_load_table(table, NULL); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { acpi_os_printf diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index b71ce3b817ea..44e719303b58 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -304,6 +304,8 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) * * PARAMETERS: table - Pointer to a buffer containing the ACPI * table to be loaded. + * table_index - Pointer to a variable receiving the table + * index, or NULL. * * RETURN: Status * @@ -314,10 +316,10 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) * to ensure that the table is not deleted or unmapped. * ******************************************************************************/ -acpi_status acpi_load_table(struct acpi_table_header *table) +acpi_status acpi_load_table(struct acpi_table_header *table, u32 *table_index) { + u32 table_index_dummy; acpi_status status; - u32 table_index; ACPI_FUNCTION_TRACE(acpi_load_table); @@ -327,12 +329,15 @@ acpi_status acpi_load_table(struct acpi_table_header *table) return_ACPI_STATUS(AE_BAD_PARAMETER); } + if (!table_index) + table_index = &table_index_dummy; + /* Install the table and load it into the namespace */ ACPI_INFO(("Host-directed Dynamic ACPI Table Load:")); status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table), ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, - FALSE, &table_index); + FALSE, table_index); return_ACPI_STATUS(status); } @@ -340,6 +345,33 @@ ACPI_EXPORT_SYMBOL(acpi_load_table) /******************************************************************************* * + * FUNCTION: acpi_unload_table + * + * PARAMETERS: table_index - Index of the table to be unloaded. + * + * RETURN: Status + * + * DESCRIPTION: Unloads the table and deletes all namespace objects associated + * with that table. Unloading of the DSDT is not allowed. + * Note: Mainly intended to support hotplug removal of SSDTs. + * + ******************************************************************************/ +acpi_status acpi_unload_table(u32 table_index) +{ + ACPI_FUNCTION_TRACE(acpi_unload_table); + + if (!table_index) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + ACPI_INFO(("Host-directed Dynamic ACPI Table Unload:")); + return acpi_tb_unload_table(table_index); +} + +ACPI_EXPORT_SYMBOL(acpi_unload_table) + +/******************************************************************************* + * * FUNCTION: acpi_unload_parent_table * * PARAMETERS: object - Handle to any namespace object owned by diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index b372aad3b449..8681c5536bfc 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -274,7 +274,7 @@ static __init int efivar_ssdt_load(void) goto free_data; } - ret = acpi_load_table(data); + ret = acpi_load_table(data, NULL); if (ret) { pr_err("failed to load table: %d\n", ret); goto free_data; diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index 339bce0403dd..57d627d699b4 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -355,7 +355,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot) if (SN_ACPI_BASE_SUPPORT() && ssdt) { acpi_status ret; - ret = acpi_load_table((struct acpi_table_header *)ssdt); + ret = acpi_load_table((struct acpi_table_header *)ssdt, NULL); if (ACPI_FAILURE(ret)) { printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n", __func__, ret); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 15c86ce4df53..8d36a9a72532 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -487,7 +487,11 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION u8 physical)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_load_table(struct acpi_table_header *table)) + acpi_load_table(struct acpi_table_header *table, + u32 *table_index)) + +ACPI_EXTERNAL_RETURN_STATUS(acpi_status + acpi_unload_table(u32 table_index)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_unload_parent_table(acpi_handle object)) -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html