Message ID | 20231019030534.157971-1-aichao@kylinos.cn (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | [v4] platform/x86: inspur-wmi: Add platform profile support | expand |
Am 19.10.23 um 05:05 schrieb Ai Chao: > Add support for Inspur platforms to used the platform profile feature. > > This will allow users to determine and control the platform modes > between low-power, balanced and performance modes. > > Signed-off-by: Ai Chao <aichao@kylinos.cn> > --- > > v4: Add select ACPI_PLATFORM_PROFILE > v3: Remove input device, using the platform profile interface > v2: Remove Event GUID, remove inspur_wmi_notify and inspur_wmi_notify. > > drivers/platform/x86/Kconfig | 11 ++ > drivers/platform/x86/Makefile | 3 + > drivers/platform/x86/inspur-wmi.c | 216 ++++++++++++++++++++++++++++++ > 3 files changed, 230 insertions(+) > create mode 100644 drivers/platform/x86/inspur-wmi.c I agree with Thomas Weißschuh that the driver name is a bit too generic, assuming the WMI hotkey driver will appear sometime too. Other than that, the driver seems good. Armin Wolf > > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig > index 2a1070543391..44f371876170 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -988,6 +988,17 @@ config TOUCHSCREEN_DMI > the OS-image for the device. This option supplies the missing info. > Enable this for x86 tablets with Silead or Chipone touchscreens. > > +config INSPUR_WMI > + tristate "Inspur WMI platform profile driver" > + depends on ACPI_WMI > + select ACPI_PLATFORM_PROFILE > + help > + This will allow users to determine and control the platform modes > + between low-power, balanced and performance modes. > + > + To compile this driver as a module, choose M here: the module > + will be called inspur-wmi. > + > source "drivers/platform/x86/x86-android-tablets/Kconfig" > > config FW_ATTR_CLASS > diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile > index b457de5abf7d..9285c252757e 100644 > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o > # before toshiba_acpi initializes > obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o > > +# Inspur > +obj-$(CONFIG_INSPUR_WMI) += inspur-wmi.o > + > # Laptop drivers > obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o > obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o > diff --git a/drivers/platform/x86/inspur-wmi.c b/drivers/platform/x86/inspur-wmi.c > new file mode 100644 > index 000000000000..243f31dd162c > --- /dev/null > +++ b/drivers/platform/x86/inspur-wmi.c > @@ -0,0 +1,216 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Inspur WMI power mode > + * > + * Copyright (C) 2018 Ai Chao <aichao@kylinos.cn> > + */ > + > +#include <linux/acpi.h> > +#include <linux/device.h> > +#include <linux/module.h> > +#include <linux/platform_profile.h> > +#include <linux/wmi.h> > + > +#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D" > + > +enum inspur_wmi_method_ids { > + INSPUR_WMI_GET_POWERMODE = 0x02, > + INSPUR_WMI_SET_POWERMODE = 0x03, > +}; > + > +/** > + * Power Mode: > + * 0x0: Balance Mode > + * 0x1: Performance Mode > + * 0x2: Power Saver Mode > + */ > +enum inspur_tmp_profile { > + INSPUR_TMP_PROFILE_BALANCE = 0, > + INSPUR_TMP_PROFILE_PERFORMANCE = 1, > + INSPUR_TMP_PROFILE_POWERSAVE = 2, > +}; > + > +struct inspur_wmi_priv { > + struct wmi_device *wdev; > + struct platform_profile_handler handler; > +}; > + > +static int inspur_wmi_perform_query(struct wmi_device *wdev, > + enum inspur_wmi_method_ids query_id, > + void *buffer, size_t insize, > + size_t outsize) > +{ > + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; > + struct acpi_buffer input = { insize, buffer}; > + union acpi_object *obj; > + acpi_status status; > + int ret = 0; > + > + status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output); > + if (ACPI_FAILURE(status)) { > + dev_err(&wdev->dev, "EC Powermode control failed: %s\n", > + acpi_format_exception(status)); > + return -EIO; > + } > + > + obj = output.pointer; > + if (!obj) > + return -EINVAL; > + > + if (obj->type != ACPI_TYPE_BUFFER || > + obj->buffer.length != outsize) { > + ret = -EINVAL; > + goto out_free; > + } > + > + memcpy(buffer, obj->buffer.pointer, obj->buffer.length); > + > +out_free: > + kfree(obj); > + return ret; > +} > + > +/** > + * Set Power Mode to EC RAM. If Power Mode value greater than 0x3, > + * return error > + * Method ID: 0x3 > + * Arg: 4 Bytes > + * Byte [0]: Power Mode: > + * 0x0: Balance Mode > + * 0x1: Performance Mode > + * 0x2: Power Saver Mode > + * Return Value: 4 Bytes > + * Byte [0]: Return Code > + * 0x0: No Error > + * 0x1: Error > + */ > +static int inspur_platform_profile_set(struct platform_profile_handler *pprof, > + enum platform_profile_option profile) > +{ > + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, > + handler); > + u8 ret_code[4] = {0, 0, 0, 0}; > + int ret; > + > + switch (profile) { > + case PLATFORM_PROFILE_BALANCED: > + ret_code[0] = INSPUR_TMP_PROFILE_BALANCE; > + break; > + case PLATFORM_PROFILE_PERFORMANCE: > + ret_code[0] = INSPUR_TMP_PROFILE_PERFORMANCE; > + break; > + case PLATFORM_PROFILE_LOW_POWER: > + ret_code[0] = INSPUR_TMP_PROFILE_POWERSAVE; > + break; > + default: > + return -EOPNOTSUPP; > + } > + > + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_SET_POWERMODE, > + ret_code, sizeof(ret_code), > + sizeof(ret_code)); > + > + if (ret < 0) > + return ret; > + > + if (ret_code[0]) > + return -EBADRQC; > + > + return 0; > +} > + > +/** > + * Get Power Mode from EC RAM, If Power Mode value greater than 0x3, > + * return error > + * Method ID: 0x2 > + * Return Value: 4 Bytes > + * Byte [0]: Return Code > + * 0x0: No Error > + * 0x1: Error > + * Byte [1]: Power Mode > + * 0x0: Balance Mode > + * 0x1: Performance Mode > + * 0x2: Power Saver Mode > + */ > +static int inspur_platform_profile_get(struct platform_profile_handler *pprof, > + enum platform_profile_option *profile) > +{ > + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, > + handler); > + u8 ret_code[4] = {0, 0, 0, 0}; > + int ret; > + > + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_GET_POWERMODE, > + &ret_code, sizeof(ret_code), > + sizeof(ret_code)); > + if (ret < 0) > + return ret; > + > + if (ret_code[0]) > + return -EBADRQC; > + > + switch (ret_code[1]) { > + case INSPUR_TMP_PROFILE_BALANCE: > + *profile = PLATFORM_PROFILE_BALANCED; > + break; > + case INSPUR_TMP_PROFILE_PERFORMANCE: > + *profile = PLATFORM_PROFILE_PERFORMANCE; > + break; > + case INSPUR_TMP_PROFILE_POWERSAVE: > + *profile = PLATFORM_PROFILE_LOW_POWER; > + break; > + default: > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int inspur_wmi_probe(struct wmi_device *wdev, const void *context) > +{ > + struct inspur_wmi_priv *priv; > + > + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + priv->wdev = wdev; > + dev_set_drvdata(&wdev->dev, priv); > + > + priv->handler.profile_get = inspur_platform_profile_get; > + priv->handler.profile_set = inspur_platform_profile_set; > + > + set_bit(PLATFORM_PROFILE_LOW_POWER, priv->handler.choices); > + set_bit(PLATFORM_PROFILE_BALANCED, priv->handler.choices); > + set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->handler.choices); > + > + return platform_profile_register(&priv->handler); > +} > + > +static void inspur_wmi_remove(struct wmi_device *wdev) > +{ > + platform_profile_remove(); > +} > + > +static const struct wmi_device_id inspur_wmi_id_table[] = { > + { .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID }, > + { } > +}; > + > +MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table); > + > +static struct wmi_driver inspur_wmi_driver = { > + .driver = { > + .name = "inspur-wmi", > + .probe_type = PROBE_PREFER_ASYNCHRONOUS, > + }, > + .id_table = inspur_wmi_id_table, > + .probe = inspur_wmi_probe, > + .remove = inspur_wmi_remove, > +}; > + > +module_wmi_driver(inspur_wmi_driver); > + > +MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>"); > +MODULE_DESCRIPTION("Inspur WMI Platform Profile"); > +MODULE_LICENSE("GPL");
Hi Ai, kernel test robot noticed the following build warnings: [auto build test WARNING on linus/master] [also build test WARNING on v6.6-rc7 next-20231023] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Ai-Chao/platform-x86-inspur-wmi-Add-platform-profile-support/20231019-110800 base: linus/master patch link: https://lore.kernel.org/r/20231019030534.157971-1-aichao%40kylinos.cn patch subject: [PATCH v4] platform/x86: inspur-wmi: Add platform profile support config: x86_64-allyesconfig (https://download.01.org/0day-ci/archive/20231024/202310240736.pU47RVwI-lkp@intel.com/config) compiler: gcc-12 (Debian 12.2.0-14) 12.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231024/202310240736.pU47RVwI-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202310240736.pU47RVwI-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/platform/x86/inspur-wmi.c:27: warning: cannot understand function prototype: 'enum inspur_tmp_profile ' drivers/platform/x86/inspur-wmi.c:74: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Set Power Mode to EC RAM. If Power Mode value greater than 0x3, drivers/platform/x86/inspur-wmi.c:123: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Get Power Mode from EC RAM, If Power Mode value greater than 0x3, vim +27 drivers/platform/x86/inspur-wmi.c 20 21 /** 22 * Power Mode: 23 * 0x0: Balance Mode 24 * 0x1: Performance Mode 25 * 0x2: Power Saver Mode 26 */ > 27 enum inspur_tmp_profile { 28 INSPUR_TMP_PROFILE_BALANCE = 0, 29 INSPUR_TMP_PROFILE_PERFORMANCE = 1, 30 INSPUR_TMP_PROFILE_POWERSAVE = 2, 31 }; 32
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 2a1070543391..44f371876170 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -988,6 +988,17 @@ config TOUCHSCREEN_DMI the OS-image for the device. This option supplies the missing info. Enable this for x86 tablets with Silead or Chipone touchscreens. +config INSPUR_WMI + tristate "Inspur WMI platform profile driver" + depends on ACPI_WMI + select ACPI_PLATFORM_PROFILE + help + This will allow users to determine and control the platform modes + between low-power, balanced and performance modes. + + To compile this driver as a module, choose M here: the module + will be called inspur-wmi. + source "drivers/platform/x86/x86-android-tablets/Kconfig" config FW_ATTR_CLASS diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index b457de5abf7d..9285c252757e 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -98,6 +98,9 @@ obj-$(CONFIG_TOSHIBA_WMI) += toshiba-wmi.o # before toshiba_acpi initializes obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o +# Inspur +obj-$(CONFIG_INSPUR_WMI) += inspur-wmi.o + # Laptop drivers obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o diff --git a/drivers/platform/x86/inspur-wmi.c b/drivers/platform/x86/inspur-wmi.c new file mode 100644 index 000000000000..243f31dd162c --- /dev/null +++ b/drivers/platform/x86/inspur-wmi.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Inspur WMI power mode + * + * Copyright (C) 2018 Ai Chao <aichao@kylinos.cn> + */ + +#include <linux/acpi.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/platform_profile.h> +#include <linux/wmi.h> + +#define WMI_INSPUR_POWERMODE_BIOS_GUID "596C31E3-332D-43C9-AEE9-585493284F5D" + +enum inspur_wmi_method_ids { + INSPUR_WMI_GET_POWERMODE = 0x02, + INSPUR_WMI_SET_POWERMODE = 0x03, +}; + +/** + * Power Mode: + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + */ +enum inspur_tmp_profile { + INSPUR_TMP_PROFILE_BALANCE = 0, + INSPUR_TMP_PROFILE_PERFORMANCE = 1, + INSPUR_TMP_PROFILE_POWERSAVE = 2, +}; + +struct inspur_wmi_priv { + struct wmi_device *wdev; + struct platform_profile_handler handler; +}; + +static int inspur_wmi_perform_query(struct wmi_device *wdev, + enum inspur_wmi_method_ids query_id, + void *buffer, size_t insize, + size_t outsize) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_buffer input = { insize, buffer}; + union acpi_object *obj; + acpi_status status; + int ret = 0; + + status = wmidev_evaluate_method(wdev, 0, query_id, &input, &output); + if (ACPI_FAILURE(status)) { + dev_err(&wdev->dev, "EC Powermode control failed: %s\n", + acpi_format_exception(status)); + return -EIO; + } + + obj = output.pointer; + if (!obj) + return -EINVAL; + + if (obj->type != ACPI_TYPE_BUFFER || + obj->buffer.length != outsize) { + ret = -EINVAL; + goto out_free; + } + + memcpy(buffer, obj->buffer.pointer, obj->buffer.length); + +out_free: + kfree(obj); + return ret; +} + +/** + * Set Power Mode to EC RAM. If Power Mode value greater than 0x3, + * return error + * Method ID: 0x3 + * Arg: 4 Bytes + * Byte [0]: Power Mode: + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + * Return Value: 4 Bytes + * Byte [0]: Return Code + * 0x0: No Error + * 0x1: Error + */ +static int inspur_platform_profile_set(struct platform_profile_handler *pprof, + enum platform_profile_option profile) +{ + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, + handler); + u8 ret_code[4] = {0, 0, 0, 0}; + int ret; + + switch (profile) { + case PLATFORM_PROFILE_BALANCED: + ret_code[0] = INSPUR_TMP_PROFILE_BALANCE; + break; + case PLATFORM_PROFILE_PERFORMANCE: + ret_code[0] = INSPUR_TMP_PROFILE_PERFORMANCE; + break; + case PLATFORM_PROFILE_LOW_POWER: + ret_code[0] = INSPUR_TMP_PROFILE_POWERSAVE; + break; + default: + return -EOPNOTSUPP; + } + + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_SET_POWERMODE, + ret_code, sizeof(ret_code), + sizeof(ret_code)); + + if (ret < 0) + return ret; + + if (ret_code[0]) + return -EBADRQC; + + return 0; +} + +/** + * Get Power Mode from EC RAM, If Power Mode value greater than 0x3, + * return error + * Method ID: 0x2 + * Return Value: 4 Bytes + * Byte [0]: Return Code + * 0x0: No Error + * 0x1: Error + * Byte [1]: Power Mode + * 0x0: Balance Mode + * 0x1: Performance Mode + * 0x2: Power Saver Mode + */ +static int inspur_platform_profile_get(struct platform_profile_handler *pprof, + enum platform_profile_option *profile) +{ + struct inspur_wmi_priv *priv = container_of(pprof, struct inspur_wmi_priv, + handler); + u8 ret_code[4] = {0, 0, 0, 0}; + int ret; + + ret = inspur_wmi_perform_query(priv->wdev, INSPUR_WMI_GET_POWERMODE, + &ret_code, sizeof(ret_code), + sizeof(ret_code)); + if (ret < 0) + return ret; + + if (ret_code[0]) + return -EBADRQC; + + switch (ret_code[1]) { + case INSPUR_TMP_PROFILE_BALANCE: + *profile = PLATFORM_PROFILE_BALANCED; + break; + case INSPUR_TMP_PROFILE_PERFORMANCE: + *profile = PLATFORM_PROFILE_PERFORMANCE; + break; + case INSPUR_TMP_PROFILE_POWERSAVE: + *profile = PLATFORM_PROFILE_LOW_POWER; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int inspur_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct inspur_wmi_priv *priv; + + priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->wdev = wdev; + dev_set_drvdata(&wdev->dev, priv); + + priv->handler.profile_get = inspur_platform_profile_get; + priv->handler.profile_set = inspur_platform_profile_set; + + set_bit(PLATFORM_PROFILE_LOW_POWER, priv->handler.choices); + set_bit(PLATFORM_PROFILE_BALANCED, priv->handler.choices); + set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->handler.choices); + + return platform_profile_register(&priv->handler); +} + +static void inspur_wmi_remove(struct wmi_device *wdev) +{ + platform_profile_remove(); +} + +static const struct wmi_device_id inspur_wmi_id_table[] = { + { .guid_string = WMI_INSPUR_POWERMODE_BIOS_GUID }, + { } +}; + +MODULE_DEVICE_TABLE(wmi, inspur_wmi_id_table); + +static struct wmi_driver inspur_wmi_driver = { + .driver = { + .name = "inspur-wmi", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table = inspur_wmi_id_table, + .probe = inspur_wmi_probe, + .remove = inspur_wmi_remove, +}; + +module_wmi_driver(inspur_wmi_driver); + +MODULE_AUTHOR("Ai Chao <aichao@kylinos.cn>"); +MODULE_DESCRIPTION("Inspur WMI Platform Profile"); +MODULE_LICENSE("GPL");
Add support for Inspur platforms to used the platform profile feature. This will allow users to determine and control the platform modes between low-power, balanced and performance modes. Signed-off-by: Ai Chao <aichao@kylinos.cn> --- v4: Add select ACPI_PLATFORM_PROFILE v3: Remove input device, using the platform profile interface v2: Remove Event GUID, remove inspur_wmi_notify and inspur_wmi_notify. drivers/platform/x86/Kconfig | 11 ++ drivers/platform/x86/Makefile | 3 + drivers/platform/x86/inspur-wmi.c | 216 ++++++++++++++++++++++++++++++ 3 files changed, 230 insertions(+) create mode 100644 drivers/platform/x86/inspur-wmi.c