Re: [PATCH] acpi: configfs: Unload SSDT on configfs entry removal

From: Mika Westerberg
Date: Mon May 29 2017 - 08:48:05 EST


On Mon, May 29, 2017 at 01:33:29PM +0200, Jan Kiszka wrote:
> 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?

IIRC ACPICA relies the fact that SSDTs are never unloaded. Bob (CC'd)
can correct me if I got it wrong.

> 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