Hi,

> From: linux-acpi-ow...@vger.kernel.org [mailto:linux-acpi-
> ow...@vger.kernel.org] On Behalf Of Octavian Purdila
> Subject: [RFC PATCH 10/10] acpi: add support for loading SSDTs via configfs
> 
> Add support for acpi_user_table configfs items that allows the user to
> load new tables. The data attributes contains the table data and once it
> is filled from userspace the table is loaded and ACPI devices are
> enumerated.
[Lv Zheng] 
We've been considering to implement this facility before.
The 2 alternative solutions are:
1. implement LOAD/UNLOAD ioctl for /sys/kernel/debug/acpi/acpidbg - this will 
be useful for extracting AML byte stream from kernel to be used by a userspace 
disassembler.
2. transition /sys/firmware/acpi/tables/xxx into directory and implement 
/sys/firmware/acpi/tables/load, /sys/firmware/acpi/tables/unload - this should 
be able to meet your requirement.

So my first question is:
Why do you use configfs rather than the existing mechanisms?

> 
> Signed-off-by: Octavian Purdila <octavian.purd...@intel.com>
> ---
>  Documentation/ABI/testing/configfs-acpi |  16 +++++
>  Documentation/acpi/ssdt-overlays.txt    |  14 +++++
>  drivers/acpi/configfs.c                 | 104 
> ++++++++++++++++++++++++++++++++
>  3 files changed, 134 insertions(+)
> 
> diff --git a/Documentation/ABI/testing/configfs-acpi
> b/Documentation/ABI/testing/configfs-acpi
> index 0c806aa..34a205e 100644
> --- a/Documentation/ABI/testing/configfs-acpi
> +++ b/Documentation/ABI/testing/configfs-acpi
> @@ -5,3 +5,19 @@ Contact:     linux-a...@vger.kernel.org
>  Description:
>               This represents the ACPI subsystem entry point directory. It
>               contains sub-groups corresponding to ACPI configurable
> options.
> +
> +What:                /config/acpi/table
> +Date:                April 2016
> +KernelVersion:       4.6
> +Description:
> +
> +             This group contains the configuration for user defined ACPI
> +             tables. The attributes of a user define table are:
> +
> +             data - a binary write only attribute that the user can use to
> +                    fill in the ACPI aml definitions. Once the aml data is
> +                    written to this file and the file is closed the table
> +                    will be loaded and ACPI device will be enumerated. To
> +                    check if the operation is successful the user must check
> +                    the error code for close(). If the operation is
> +                    successful, subsequent writes to this attribute will 
> fail.
> diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-
> overlays.txt
> index 7c588be..a88a2ce 100644
> --- a/Documentation/acpi/ssdt-overlays.txt
> +++ b/Documentation/acpi/ssdt-overlays.txt
> @@ -158,3 +158,17 @@ tmp=$(mktemp)
>  /bin/echo -ne "\007\000\000\000" | cat - $filename > $tmp
>  dd if=$tmp of="$EFIVARFS/$name-$guid" bs=$(stat -c %s $tmp)
>  rm $tmp
> +
> +== Loading ACPI SSDTs from configfs ==
> +
> +This option allows loading of user defined SSDTs from userspace via the
> configfs
> +interface. The CONFIG_ACPI_CONFIGFS option must be select and configfs
> must be
> +mounted. In the following examples, we assume that configfs has been
> mounted in
> +/config.
> +
> +New tables can be loading by creating new directories in /config/acpi/table/
> and
> +writing the SSDT aml code in the data attribute:
> +
> +cd /config/acpi/table
> +mkdir my_ssdt
> +cat ~/ssdt.aml > my_ssdt/data
[Lv Zheng] 
Good to see the table as a directory.
So that we can put more attributes under it.

Thanks
-Lv

> diff --git a/drivers/acpi/configfs.c b/drivers/acpi/configfs.c
> index 96aa3d8..3a194806 100644
> --- a/drivers/acpi/configfs.c
> +++ b/drivers/acpi/configfs.c
> @@ -13,6 +13,104 @@
>  #include <linux/configfs.h>
>  #include <linux/acpi.h>
> 
> +static struct config_group *acpi_table_group;
> +
> +struct acpi_user_table {
> +     struct config_item cfg;
> +     struct acpi_table_header *table;
> +};
> +
> +static ssize_t acpi_table_data_write(struct config_item *cfg,
> +                                  const void *data, size_t size)
> +{
> +     struct acpi_table_header *header = (struct acpi_table_header *)data;
> +     struct acpi_user_table *table;
> +     int ret;
> +
> +     table = container_of(cfg, struct acpi_user_table, cfg);
> +
> +     if (table->table) {
> +             pr_err("ACPI configfs table: table already loaded\n");
> +             return -EBUSY;
> +     }
> +
> +     if (header->length != size) {
> +             pr_err("ACPI configfs table: invalid table length\n");
> +             return -EINVAL;
> +     }
> +
> +     if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
> +             pr_err("ACPI configfs table: invalid table signature\n");
> +             return -EINVAL;
> +     }
> +
> +     table = container_of(cfg, struct acpi_user_table, cfg);
> +
> +     table->table = kmemdup(header, header->length, GFP_KERNEL);
> +     if (!table->table)
> +             return -ENOMEM;
> +
> +     ret = acpi_load_table(table->table);
> +     if (ret) {
> +             kfree(table->table);
> +             table->table = NULL;
> +     }
> +
> +     add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
> +
> +     return ret;
> +}
> +
> +#define MAX_ACPI_TABLE_SIZE (128 * 1024)
> +
> +CONFIGFS_BIN_ATTR_WO(acpi_table_, data, NULL, MAX_ACPI_TABLE_SIZE);
> +
> +struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
> +     &acpi_table_attr_data,
> +     NULL,
> +};
> +
> +static struct config_item_type acpi_table_type = {
> +     .ct_owner = THIS_MODULE,
> +     .ct_bin_attrs = acpi_table_bin_attrs,
> +};
> +
> +static struct config_item *acpi_table_make_item(struct config_group *group,
> +                                             const char *name)
> +{
> +     struct acpi_user_table *table;
> +
> +     table = kzalloc(sizeof(*table), GFP_KERNEL);
> +     if (!table)
> +             return ERR_PTR(-ENOMEM);
> +
> +     config_item_init_type_name(&table->cfg, name, &acpi_table_type);
> +     return &table->cfg;
> +}
> +
> +struct configfs_group_operations acpi_table_group_ops = {
> +     .make_item = acpi_table_make_item,
> +};
> +
> +static struct config_item_type acpi_tables_type = {
> +     .ct_owner = THIS_MODULE,
> +     .ct_group_ops = &acpi_table_group_ops,
> +};
> +
> +static struct config_item_type acpi_root_group_type = {
> +     .ct_owner       = THIS_MODULE,
> +};
> +
> +static struct configfs_subsystem acpi_configfs = {
> +     .su_group = {
> +             .cg_item = {
> +                     .ci_namebuf = "acpi",
> +                     .ci_type = &acpi_root_group_type,
> +             },
> +     },
> +     .su_mutex = __MUTEX_INITIALIZER(acpi_configfs.su_mutex),
> +};
> +
>  static int __init acpi_configfs_init(void)
>  {
>       int ret;
> @@ -24,12 +122,18 @@ static int __init acpi_configfs_init(void)
>       if (ret)
>               return ret;
> 
> +     acpi_table_group = configfs_register_default_group(root, "table",
> +                                                        &acpi_tables_type);
> +     if (IS_ERR(acpi_table_group))
> +             return PTR_ERR(acpi_table_group);
> +
>       return 0;
>  }
>  module_init(acpi_configfs_init);
> 
>  static void __exit acpi_configfs_exit(void)
>  {
> +     configfs_unregister_default_group(acpi_table_group);
>       configfs_unregister_subsystem(&acpi_configfs);
>  }
>  module_exit(acpi_configfs_exit);
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to