platform-x86: lenovo-wmi: Add fixes and enhancement
Subsystems (5)
Derek J. Clark
maintainerv5 cover platform-x86: lenovo-wmi: Add fixes and enhancement
This series adds many much needed features and fixes to the lenovo-wmi drivers.
Patch 1 moves LWMI_FAN_DIV to be next to the rest of the fan attribute defines in preparation for adding additional attrbiute macros. This is so the attribute macros can all be in the same place in the file.
Patch 2 cleans up tunable_attr_01 by removing an unused pointer and correctly assigning the members as u8 isntead of u32.
Patch 3 adds a function to make assigning attribute ID's for capdata cleaner and easier.
Patch 4 addresses bugs where devices that don't support exposed attributes would still create the attribute, and also attempts to identify the correct capdata and set/get methods as some legacy interfaces don't use the custom mode in the method or capdata ID.
Patch 5 adds the remaining CPU attributes that weren't previously exposed.
Patch 6 adds GPU attributes.
Patch 7 renames a name constant in preparation for patch 6.
Patch 8 adds battery charge-type limiting when supported only by WMI, or when a module parameter to skip this check is set. The MODULE_PARM_DESC macro creates one check and two warnings in checkpatch. I reviewed other examples from the kernel and I am following the same convention, so I left it as is.
---
v5:
- Remove cv/cd_mode_id references that occured before patch 4.
- Move lwmi_attr_id to capdata.c with a namespace export.
- Fix mixing include.
- Make lwmi_attr_is_supported return bool.
- Use switch instead of if for setting/getting charge type state.
- Various formatting fixes.
v4: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Use loop instead of back gotos for identifying the working attribute
ID.
- Use function instead of macro to assign attribute_id, preserving
types.
- Removed unused defines and enum values.
- Rename charging defines to clarify thier purpose.
- Fixed various formatting issues from v3.
- Added module param to skip ACPI check when loading the driver for
the power supply extension.
- Don't abort adding power supply extension if the ACPI handle from
ideapad is not present.
- Don't worry about symmetric cleanup when cleaning up attributes in
an error state.
- Reword Patch 8 commit message to be more concise.
- Fix wording in Patch 7 to match the changes.
v3: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Re-add HWMON name const and just rename LWMI_OM_FW_ATTR_BASE_PATH
- Fix linker warnings by moving acpi/battery include to the end of the
list.
- Remove CPU/GPU OC features. These attributes are BOOL type and will
need a new constructor that I'll add later.
v2: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Fix gpu_mode misisng from attributes list.
- Fix prototypes for power suppy patch.
- Reorganize CPU and GPU attributes alphabetically.
- Break out the patch consolidating the driver name cost.
- Move some of the refactoring of attribute_id back to into patch 1
where it belongs.
- Fix some additional typos in function prototypes.
v1: https://lore.kernel.org/platform-driver-x86/[email protected]/
Derek J. Clark (8):
platform-x86: lenovo-wmi-other: Move LWMI_FAN_DIV
platform-x86: lenovo-wmi-other: Fix tunable_attr_01 struct members platform/x86: lenovo-wmi-other: Add lwmi_attr_id() function platform/x86: lenovo-wmi-other: Limit adding attributes to supported
devices
platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes platform/x86: lenovo-wmi-other: Add GPU tunable attributes
platform-x86: lenovo-wmi-other: Rename LWMI_OM_FW_ATTR_BASE_PATH platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
.../wmi/devices/lenovo-wmi-other.rst | 19 + drivers/platform/x86/lenovo/Kconfig | 1 + drivers/platform/x86/lenovo/wmi-capdata.c | 25 +- drivers/platform/x86/lenovo/wmi-capdata.h | 10 +- drivers/platform/x86/lenovo/wmi-gamezone.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 586 ++++++++++++++++-- 6 files changed, 596 insertions(+), 46 deletions(-)
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 1/8 platform-x86: lenovo-wmi-other: Move LWMI_FAN_DIV
Later patches in this series will add additional attribute ID macros. Keep the fan defines together and permit attribute ID macros to stay together as well by moving LWMI_FAN_DIV.
--- drivers/platform/x86/lenovo/wmi-other.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +2 -2
@@ -71,13 +71,13 @@#define LWMI_FAN_NR 4#define LWMI_FAN_ID (x) ((x) + LWMI_FAN_ID_BASE) +#define LWMI_FAN_DIV 100 +#define LWMI_ATTR_ID_FAN_RPM (x) \ (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \ FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x))) -#define LWMI_FAN_DIV 100 -#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 2/8 platform-x86: lenovo-wmi-other: Fix tunable_attr_01 struct members
In reply to Derek J. ClarkIn struct tunable_attr_01 the capdata pointer is unused and the size of the id members is u32 when it should be u8. Fix these prior to adding additional members.
--- drivers/platform/x86/lenovo/wmi-other.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +3 -4
@@ -546,11 +546,10 @@ static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list */* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */ struct tunable_attr_01 { -struct capdata01 *capdata;struct device *dev; -u32 feature_id; -u32 device_id; -u32 type_id; +u8 feature_id; +u8 device_id; +u8 type_id; };static struct tunable_attr_01 ppt_pl1_spl = {
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 3/8 platform/x86: lenovo-wmi-other: Add lwmi_attr_id() function
In reply to Derek J. ClarkAdds lwmi_attr_id() function. In the same vein as LWMI_ATTR_ID_FAN_RPM(), but as a generic, to de-duplicate attribute_id assignment biolerplate.
---
v5:
- Move references to cv/cd_mode_id to patch 4/8.
- Move lwmi_attr_id to wmi-capdata.c and export with namespace.
v4:
- Switch from macro to static inline to preserve types.
--- drivers/platform/x86/lenovo/wmi-capdata.c | 25 ++++++++++++-- drivers/platform/x86/lenovo/wmi-capdata.h | 3 ++ drivers/platform/x86/lenovo/wmi-gamezone.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 39 ++++++---------------- 4 files changed, 36 insertions(+), 32 deletions(-)
drivers/platform/x86/lenovo/wmi-capdata.c +22 -3
@@ -48,6 +48,7 @@#include <linux/wmi.h> #include "wmi-capdata.h" +#include "wmi-gamezone.h" #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
@@ -58,9 +59,27 @@#define LWMI_FEATURE_ID_FAN_TEST 0x05 -#define LWMI_ATTR_ID_FAN_TEST \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST)) +/** +* lwmi_attr_id() - Formats a capability data attribute ID +* @dev_id: The u8 corresponding to the device ID. +* @feat_id: The u8 corresponding to the feature ID on the device. +* @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get. +* @type_id: The u8 corresponding to the sub-device. +* +* Return: u32. +*/ +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id) +{ +return (FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , dev_id) | +FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , feat_id) | +FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode_id) | +FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , type_id)); +} +EXPORT_SYMBOL_NS_GPL (lwmi_attr_id,"LENOVO_WMI_CAPDATA" ); + +#define LWMI_ATTR_ID_FAN_TEST \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)enum lwmi_cd_type {LENOVO_CAPABILITY_DATA_00 ,
drivers/platform/x86/lenovo/wmi-capdata.h +3 -0
@@ -19,6 +19,8 @@#define LWMI_DEVICE_ID_FAN 0x04 +#define LWMI_TYPE_ID_NONE 0x00 +struct component_match ;struct device ;struct cd_list ;
@@ -57,6 +59,7 @@ struct lwmi_cd_binder {cd_list_cb_t cd_fan_list_cb; }; +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id);void lwmi_cd_match_add_all (struct device *master,struct component_match **matchptr);int lwmi_cd00_get_data (struct cd_list *list,u32 attribute_id,struct capdata00 *output);int lwmi_cd01_get_data (struct cd_list *list,u32 attribute_id,struct capdata01 *output);
drivers/platform/x86/lenovo/wmi-gamezone.h +1 -0
@@ -10,6 +10,7 @@ enum gamezone_events_type { };enum thermal_mode { +LWMI_GZ_THERMAL_MODE_NONE =0x00 ,LWMI_GZ_THERMAL_MODE_QUIET =0x01 ,LWMI_GZ_THERMAL_MODE_BALANCED =0x02 ,LWMI_GZ_THERMAL_MODE_PERFORMANCE =0x03 ,
drivers/platform/x86/lenovo/wmi-other.c +10 -29
@@ -27,7 +27,6 @@*/ #include <linux/acpi.h> -#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/component.h> #include <linux/container_of.h>
@@ -62,8 +61,6 @@#define LWMI_FEATURE_ID_FAN_RPM 0x03 -#define LWMI_TYPE_ID_NONE 0x00 -#define LWMI_FEATURE_VALUE_GET 17#define LWMI_FEATURE_VALUE_SET 18
@@ -73,10 +70,9 @@#define LWMI_FAN_DIV 100 -#define LWMI_ATTR_ID_FAN_RPM (x) \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \ - FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x))) +#define LWMI_ATTR_ID_FAN_RPM (x) \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
@@ -715,12 +711,8 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,u32 attribute_id;int value, ret; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , -LWMI_GZ_THERMAL_MODE_CUSTOM ) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + attribute_id =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, +LWMI_GZ_THERMAL_MODE_CUSTOM , tunable_attr->type_id); ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata);if (ret)
@@ -775,7 +767,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,struct wmi_method_args_32 args;struct capdata01 capdata;enum thermal_mode mode; -u32 attribute_id;u32 value;int ret;
@@ -786,13 +777,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (mode !=LWMI_GZ_THERMAL_MODE_CUSTOM )return -EBUSY ; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id); - ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata); + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)return ret;
@@ -803,7 +791,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (value < capdata.min_value || value > capdata.max_value)return -EINVAL ; - args.arg0 = attribute_id; args.arg1 = value; ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
@@ -837,7 +824,6 @@ static ssize_t attr_current_value_show(struct kobject *kobj,struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev);struct wmi_method_args_32 args;enum thermal_mode mode; -u32 attribute_id;int retval;int ret;
@@ -845,13 +831,8 @@ static ssize_t attr_current_value_show(struct kobject *kobj,if (ret)return ret; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); - - args.arg0 = attribute_id; + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id); ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, (unsigned char *)&args, sizeof(args),
Signature · 1 line
2.53.0
Re: [PATCH v5 3/8] platform/x86: lenovo-wmi-other: Add lwmi_attr_id() function
Hi Derek,
Quoted 48 lines · Derek J. Clark
Adds
lwmi_attr_id()function. In the same vein asLWMI_ATTR_ID_FAN_RPM(), but as a generic, to de-duplicateattribute_idassignment biolerplate.Reviewed-by Mark Pearson <[email protected]>Signed-off-by Derek J. Clark <[email protected]>---
v5:
- Move references to cv/cd_mode_id to patch 4/8.
- Movelwmi_attr_idtowmi-capdata.cand export with namespace.
v4:
- Switch from macro to static inline to preserve types.--- drivers/platform/x86/lenovo/wmi-capdata.c | 25 ++++++++++++-- drivers/platform/x86/lenovo/wmi-capdata.h | 3 ++ drivers/platform/x86/lenovo/wmi-gamezone.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 39 ++++++---------------- 4 files changed, 36 insertions(+), 32 deletions(-)drivers/platform/x86/lenovo/wmi-capdata.c +12
-3@@ -48,6 +48,7 @@#include <linux/wmi.h> #include "wmi-capdata.h" +#include "wmi-gamezone.h" #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"@@ -58,9 +59,27 @@#define LWMI_FEATURE_ID_FAN_TEST 0x05 -#define LWMI_ATTR_ID_FAN_TEST \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST)) +/** +* lwmi_attr_id() - Formats a capability data attribute ID +* @dev_id: The u8 corresponding to the device ID. +* @feat_id: The u8 corresponding to the feature ID on the device. +* @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get. +* @type_id: The u8 corresponding to the sub-device. +* +* Return: u32. +*/ +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id) +{
drivers/platform/x86/lenovo/wmi-capdata.c line 82
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-capdata.c +10
-0+return (FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , dev_id) | +FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , feat_id) | +FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode_id) | +FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , type_id)); +} +EXPORT_SYMBOL_NS_GPL (lwmi_attr_id,"LENOVO_WMI_CAPDATA" ); + +#define LWMI_ATTR_ID_FAN_TEST \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)
I don't really love the idea of exporting a very simple function instead of providing a static inline equivalent in the corresponding header.
Compilers are smart. For example, they are capable to convert LWMI_ATTR_ID_FAN_RPM(x) into `0x04030000 | (x + 1)', as long as the function body is accessible.
By implementing and exporting it in wmi-capdata.c, wmi-other.c can no longer access the function body so no optimization can be done there (note that LTO has nothing to do when both are compiled as modules). Hence, the compiler has no choice but to emit a function call to lwmi_attr_id().
Moreover, your following patches have a lot of lwmi_attr_id(tunable_attr->*_id, ...) patterns in wmi-other.c. Outlining a simple function usually has higher overhead than inlining it (hence worse performance). The calling convention also increases register pressure, resulting in a bloated code size:
PATCH v5 (whole series):
text data bss dec hex filename 6465 1832 0 8297 2069 lenovo-wmi-capdata.ko 43132 9153 3 52288 cc40 lenovo-wmi-other.ko
Inlining lwmi_attr_id():
text data bss dec hex filename 6325 1832 0 8157 1fdd lenovo-wmi-capdata.ko 41070 9153 3 50226 c432 lenovo-wmi-other.ko
52288 - 50226 ~= 2KiB, which is quite a lot.
So please move it to capdata.h and make it a static inline function.
Quoted 130 lines
drivers/platform/x86/lenovo/wmi-capdata.c +0
-0enum lwmi_cd_type {LENOVO_CAPABILITY_DATA_00 ,drivers/platform/x86/lenovo/wmi-capdata.h +3
-0@@ -19,6 +19,8 @@#define LWMI_DEVICE_ID_FAN 0x04 +#define LWMI_TYPE_ID_NONE 0x00 +struct component_match ;struct device ;struct cd_list ;@@ -57,6 +59,7 @@ struct lwmi_cd_binder {cd_list_cb_t cd_fan_list_cb; }; +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id);void lwmi_cd_match_add_all (struct device *master,struct component_match **matchptr);int lwmi_cd00_get_data (struct cd_list *list,u32 attribute_id,struct capdata00 *output);int lwmi_cd01_get_data (struct cd_list *list,u32 attribute_id,struct capdata01 *output);drivers/platform/x86/lenovo/wmi-gamezone.h +1
-0@@ -10,6 +10,7 @@ enum gamezone_events_type { };enum thermal_mode { +LWMI_GZ_THERMAL_MODE_NONE =0x00 ,LWMI_GZ_THERMAL_MODE_QUIET =0x01 ,LWMI_GZ_THERMAL_MODE_BALANCED =0x02 ,LWMI_GZ_THERMAL_MODE_PERFORMANCE =0x03 ,drivers/platform/x86/lenovo/wmi-other.c +8
-22@@ -27,7 +27,6 @@*/ #include <linux/acpi.h> -#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/component.h> #include <linux/container_of.h> @@ -62,8 +61,6 @@#define LWMI_FEATURE_ID_FAN_RPM 0x03 -#define LWMI_TYPE_ID_NONE 0x00 -#define LWMI_FEATURE_VALUE_GET 17#define LWMI_FEATURE_VALUE_SET 18@@ -73,10 +70,9 @@#define LWMI_FAN_DIV 100 -#define LWMI_ATTR_ID_FAN_RPM (x) \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \ - FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x))) +#define LWMI_ATTR_ID_FAN_RPM (x) \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"@@ -715,12 +711,8 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,u32 attribute_id;int value, ret; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , -LWMI_GZ_THERMAL_MODE_CUSTOM ) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + attribute_id =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, +LWMI_GZ_THERMAL_MODE_CUSTOM , tunable_attr->type_id); ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata);if (ret)@@ -775,7 +767,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,struct wmi_method_args_32 args;struct capdata01 capdata;enum thermal_mode mode; -u32 attribute_id;u32 value;int ret;@@ -786,13 +777,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (mode !=LWMI_GZ_THERMAL_MODE_CUSTOM )return -EBUSY ; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id); - ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata); + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)return ret;@@ -803,7 +791,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (value < capdata.min_value || value > capdata.max_value)return -EINVAL ; - args.arg0 = attribute_id; args.arg1 = value; ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,@@ -837,7 +824,6 @@ static ssize_t attr_current_value_show(struct kobject *kobj,struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev);struct wmi_method_args_32 args;enum thermal_mode mode; -u32 attribute_id;int retval;int ret;@@ -845,13 +831,8 @@ static ssize_t attr_current_value_show(struct kobject *kobj,if (ret)return ret;
drivers/platform/x86/lenovo/wmi-other.c static ssize_t attr_current_value_show(struct kobject *kobj, · line 835
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +2
-7- attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); - - args.arg0 = attribute_id; + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id);
IIUC args.arg1 contains uninitialized data and will be passed to firmware. Since you are revising its assignment, let's zero-initialize `args' when declaring it too.
Thanks,
Rong
Quoted 3 lines
drivers/platform/x86/lenovo/wmi-other.c +0
-0ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, (unsigned char *)&args, sizeof(args),
Derek J. Clark
maintainerRe: [PATCH v5 3/8] platform/x86: lenovo-wmi-other: Add lwmi_attr_id() function
Quoted 230 lines · Rong Zhang
Hi Derek,
Quoted 48 lines · Derek J. Clark
Adds
lwmi_attr_id()function. In the same vein asLWMI_ATTR_ID_FAN_RPM(), but as a generic, to de-duplicateattribute_idassignment biolerplate.Reviewed-by Mark Pearson <[email protected]>Signed-off-by Derek J. Clark <[email protected]>---
v5:
- Move references to cv/cd_mode_id to patch 4/8.
- Movelwmi_attr_idtowmi-capdata.cand export with namespace.
v4:
- Switch from macro to static inline to preserve types.--- drivers/platform/x86/lenovo/wmi-capdata.c | 25 ++++++++++++-- drivers/platform/x86/lenovo/wmi-capdata.h | 3 ++ drivers/platform/x86/lenovo/wmi-gamezone.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 39 ++++++---------------- 4 files changed, 36 insertions(+), 32 deletions(-)drivers/platform/x86/lenovo/wmi-capdata.c +12
-3@@ -48,6 +48,7 @@#include <linux/wmi.h> #include "wmi-capdata.h" +#include "wmi-gamezone.h" #define LENOVO_CAPABILITY_DATA_00_GUID "362A3AFE-3D96-4665-8530-96DAD5BB300E"#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"@@ -58,9 +59,27 @@#define LWMI_FEATURE_ID_FAN_TEST 0x05 -#define LWMI_ATTR_ID_FAN_TEST \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_TEST)) +/** +* lwmi_attr_id() - Formats a capability data attribute ID +* @dev_id: The u8 corresponding to the device ID. +* @feat_id: The u8 corresponding to the feature ID on the device. +* @mode_id: The u8 corresponding to the wmi-gamezone mode for set/get. +* @type_id: The u8 corresponding to the sub-device. +* +* Return: u32. +*/ +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id) +{drivers/platform/x86/lenovo/wmi-capdata.c line 82
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-capdata.c +10
-0+return (FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , dev_id) | +FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , feat_id) | +FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode_id) | +FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , type_id)); +} +EXPORT_SYMBOL_NS_GPL (lwmi_attr_id,"LENOVO_WMI_CAPDATA" ); + +#define LWMI_ATTR_ID_FAN_TEST \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_TEST, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_TYPE_ID_NONE)I don't really love the idea of exporting a very simple function instead of providing a static inline equivalent in the corresponding header.
Compilers are smart. For example, they are capable to convert
LWMI_ATTR_ID_FAN_RPM(x)into `0x04030000 | (x + 1)', as long as the function body is accessible.By implementing and exporting it in
wmi-capdata.c,wmi-other.ccan no longer access the function body so no optimization can be done there (note that LTO has nothing to do when both are compiled as modules). Hence, the compiler has no choice but to emit a function call tolwmi_attr_id().Moreover, your following patches have a lot of
lwmi_attr_id(tunable_attr->*_id, ...)patterns inwmi-other.c. Outlining a simple function usually has higher overhead than inlining it (hence worse performance). The calling convention also increases register pressure, resulting in a bloated code size:PATCH v5 (whole series):
text data bss dec hex filename 6465 1832 0 8297 2069 lenovo-wmi-capdata.ko 43132 9153 3 52288 cc40 lenovo-wmi-other.koInlining
lwmi_attr_id():text data bss dec hex filename 6325 1832 0 8157 1fdd lenovo-wmi-capdata.ko 41070 9153 3 50226 c432 lenovo-wmi-other.ko52288 - 50226 ~= 2KiB, which is quite a lot.
So please move it to
capdata.hand make it a static inline function.Quoted 131 lines
drivers/platform/x86/lenovo/wmi-capdata.c +0
-0enum lwmi_cd_type {LENOVO_CAPABILITY_DATA_00 ,drivers/platform/x86/lenovo/wmi-capdata.h +3
-0@@ -19,6 +19,8 @@#define LWMI_DEVICE_ID_FAN 0x04 +#define LWMI_TYPE_ID_NONE 0x00 +struct component_match ;struct device ;struct cd_list ;@@ -57,6 +59,7 @@ struct lwmi_cd_binder {cd_list_cb_t cd_fan_list_cb; }; +u32 lwmi_attr_id (u8 dev_id,u8 feat_id,u8 mode_id,u8 type_id);void lwmi_cd_match_add_all (struct device *master,struct component_match **matchptr);int lwmi_cd00_get_data (struct cd_list *list,u32 attribute_id,struct capdata00 *output);int lwmi_cd01_get_data (struct cd_list *list,u32 attribute_id,struct capdata01 *output);drivers/platform/x86/lenovo/wmi-gamezone.h +1
-0@@ -10,6 +10,7 @@ enum gamezone_events_type { };enum thermal_mode { +LWMI_GZ_THERMAL_MODE_NONE =0x00 ,LWMI_GZ_THERMAL_MODE_QUIET =0x01 ,LWMI_GZ_THERMAL_MODE_BALANCED =0x02 ,LWMI_GZ_THERMAL_MODE_PERFORMANCE =0x03 ,drivers/platform/x86/lenovo/wmi-other.c +8
-22@@ -27,7 +27,6 @@*/ #include <linux/acpi.h> -#include <linux/bitfield.h> #include <linux/cleanup.h> #include <linux/component.h> #include <linux/container_of.h> @@ -62,8 +61,6 @@#define LWMI_FEATURE_ID_FAN_RPM 0x03 -#define LWMI_TYPE_ID_NONE 0x00 -#define LWMI_FEATURE_VALUE_GET 17#define LWMI_FEATURE_VALUE_SET 18@@ -73,10 +70,9 @@#define LWMI_FAN_DIV 100 -#define LWMI_ATTR_ID_FAN_RPM (x) \ - (FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, LWMI_DEVICE_ID_FAN) | \ - FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, LWMI_FEATURE_ID_FAN_RPM) | \ - FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, LWMI_FAN_ID(x))) +#define LWMI_ATTR_ID_FAN_RPM (x) \ + lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \ + LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x))#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"@@ -715,12 +711,8 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,u32 attribute_id;int value, ret; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , -LWMI_GZ_THERMAL_MODE_CUSTOM ) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + attribute_id =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, +LWMI_GZ_THERMAL_MODE_CUSTOM , tunable_attr->type_id); ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata);if (ret)@@ -775,7 +767,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,struct wmi_method_args_32 args;struct capdata01 capdata;enum thermal_mode mode; -u32 attribute_id;u32 value;int ret;@@ -786,13 +777,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (mode !=LWMI_GZ_THERMAL_MODE_CUSTOM )return -EBUSY ; - attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id); - ret =lwmi_cd01_get_data (priv->cd01_list, attribute_id, &capdata); + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)return ret;@@ -803,7 +791,6 @@ static ssize_t attr_current_value_store(struct kobject *kobj,if (value < capdata.min_value || value > capdata.max_value)return -EINVAL ; - args.arg0 = attribute_id; args.arg1 = value; ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,@@ -837,7 +824,6 @@ static ssize_t attr_current_value_show(struct kobject *kobj,struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev);struct wmi_method_args_32 args;enum thermal_mode mode; -u32 attribute_id;int retval;int ret;@@ -845,13 +831,8 @@ static ssize_t attr_current_value_show(struct kobject *kobj,if (ret)return ret;
Quoted 14 lines
drivers/platform/x86/lenovo/wmi-other.c static ssize_t attr_current_value_show(struct kobject *kobj, · line 835
Quoted 9 lines
drivers/platform/x86/lenovo/wmi-other.c +2
-7- attribute_id = -FIELD_PREP (LWMI_ATTR_DEV_ID_MASK , tunable_attr->device_id) | -FIELD_PREP (LWMI_ATTR_FEAT_ID_MASK , tunable_attr->feature_id) | -FIELD_PREP (LWMI_ATTR_MODE_ID_MASK , mode) | -FIELD_PREP (LWMI_ATTR_TYPE_ID_MASK , tunable_attr->type_id); - - args.arg0 = attribute_id; + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + mode, tunable_attr->type_id);IIUC args.arg1 contains uninitialized data and will be passed to firmware. Since you are revising its assignment, let's zero-initialize `args' when declaring it too.
Hi Rong,
Sure, I can do those.
Derek
Quoted 6 lines
Thanks,
RongQuoted 3 lines
drivers/platform/x86/lenovo/wmi-other.c +0
-0ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_GET, (unsigned char *)&args, sizeof(args),
Derek J. Clark
maintainerPATCH v5 4/8 platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices
In reply to Derek J. ClarkAdds lwmi_is_attr_01_supported, and only creates the attribute subfolder if the attribute is supported by the hardware. Due to some poorly implemented BIOS this is a multi-step sequence of events. This is because:
- Some BIOS support getting the capability data from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS support get/set for the current value from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS report capability data for a method that is not fully implemented.
- Some BIOS have methods fully implemented, but no complimentary capability data.
To ensure we only expose fully implemented methods with corresponding capability data, we check each outcome before reporting that an attribute can be supported.
Checking for lwmi_is_attr_01_supported during remove is not done to ensure that we don't attempt to call cd01 or send WMI events if one of the interfaces being removed was the cause of the driver unloading.
---
v5:
- Move cv/cd_mode_id refrences from path 3/4.
- Add missing import for ARRAY_SIZE.
- Make lwmi_is_attr_01_supported return bool instead of u32.
- Various formatting fixes.
v4:
- Use for loop instead of backtrace gotos for checking if an attribute is supported.
- Add include for dev_printk.
- Wrap dev_dbg in lwmi_is_attr_01_supported earlier.
- Don't use symmetric cleanup of attributes in error states.
--- drivers/platform/x86/lenovo/wmi-other.c | 87 ++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 3 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +84 -3
@@ -27,10 +27,12 @@*/ #include <linux/acpi.h> +#include <linux/array_size.h> #include <linux/cleanup.h> #include <linux/component.h> #include <linux/container_of.h> #include <linux/device.h> +#include <linux/dev_printk.h> #include <linux/export.h> #include <linux/gfp_types.h> #include <linux/hwmon.h>
@@ -546,6 +548,8 @@ struct tunable_attr_01 {u8 feature_id;u8 device_id;u8 type_id; +u8 cd_mode_id;/* mode arg for searching capdata */ +u8 cv_mode_id;/* mode arg for set/get current_value */ };static struct tunable_attr_01 ppt_pl1_spl = {
@@ -778,7 +782,7 @@ static ssize_t attr_current_value_store(struct kobject *kobj,return -EBUSY ; args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, - mode, tunable_attr->type_id); + tunable_attr->cd_mode_id, tunable_attr->type_id); ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)
@@ -831,6 +835,10 @@ static ssize_t attr_current_value_show(struct kobject *kobj,if (ret)return ret; +/* If "no-mode" is the supported mode, ensure we never send current mode */ +if (tunable_attr->cv_mode_id ==LWMI_GZ_THERMAL_MODE_NONE ) + mode = tunable_attr->cv_mode_id; + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, mode, tunable_attr->type_id);
@@ -843,6 +851,77 @@ static ssize_t attr_current_value_show(struct kobject *kobj,return sysfs_emit (buf,"%d\n" , retval); } +/** +* lwmi_attr_01_is_supported() - Determine if the given attribute is supported. +* @tunable_attr: The attribute to verify. +* +* First check if the attribute has a corresponding capdata01 table in the cd01 +* module under the "custom" mode (0xff). If that is not present then check if +* there is a corresponding "no-mode" (0x00) entry. If either of those passes, +* check capdata->supported for values > 0. If capdata is available, attempt to +* determine the set/get mode for the current value property using a similar +* pattern. If the value returned by either custom or no-mode is 0, or we get +* an error, we assume that mode is not supported. If any of the above checks +* fail then the attribute is not fully supported. +* +* The probed cd_mode_id/cv_mode_id are stored on the tunable_attr for later +* reference. +* +* Return: bool. +*/ +static bool lwmi_attr_01_is_supported (struct tunable_attr_01 *tunable_attr) +{ +u8 modes[2 ] = {LWMI_GZ_THERMAL_MODE_CUSTOM ,LWMI_GZ_THERMAL_MODE_NONE }; +struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev); +struct wmi_method_args_32 args; +bool cd_mode_found = false; +bool cv_mode_found = false; +struct capdata01 capdata; +int retval, ret, i; + +/* Determine tunable_attr->cd_mode_id*/ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + modes[i], tunable_attr->type_id); + + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata); +if (ret || !capdata.supported) +continue ; + tunable_attr->cd_mode_id = modes[i]; + cd_mode_found = true; +break ; + } + +if (!cd_mode_found) +return cd_mode_found; + +/* Determine tunable_attr->cv_mode_id, returns 1 if supported*/ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + modes[i], tunable_attr->type_id); + + ret =lwmi_dev_evaluate_int (priv->wdev,0x0 ,LWMI_FEATURE_VALUE_GET , + (unsigned char *)&args,sizeof (args), + &retval); +if (ret || !retval) +continue ; + tunable_attr->cv_mode_id = modes[i]; + cv_mode_found = true; +break ; + } + +if (!cv_mode_found) +return cv_mode_found; + +dev_dbg (tunable_attr->dev, +"cd_mode_id: %#10x, cv_mode_id: %#10x attribute support level: %#10x\n" , +lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + tunable_attr->cd_mode_id, tunable_attr->type_id), + args.arg0, capdata.supported); + +return capdata.supported >0 ? true : false; +} +/* Lenovo WMI Other Mode Attribute macros */ #define __LWMI_ATTR_RO (_func, _name) \ { \
@@ -966,12 +1045,14 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv) }for (i =0 ; i <ARRAY_SIZE (cd01_attr_groups) -1 ; i++) { + cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; +if (!lwmi_attr_01_is_supported (cd01_attr_groups[i].tunable_attr)) +continue ; + err =sysfs_create_group (&priv->fw_attr_kset->kobj, cd01_attr_groups[i].attr_group);if (err) goto err_remove_groups; - - cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; }return 0 ;
Signature · 1 line
2.53.0
Re: [PATCH v5 4/8] platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices
Hi Derek,
Quoted 104 lines · Derek J. Clark
Adds
lwmi_is_attr_01_supported, and only creates the attribute subfolder if the attribute is supported by the hardware. Due to some poorly implemented BIOS this is a multi-step sequence of events. This is because:
- Some BIOS support getting the capability data from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS support get/set for the current value from custom mode (0xff), while others only support it in no-mode (0x00).
- Some BIOS report capability data for a method that is not fully implemented.
- Some BIOS have methods fully implemented, but no complimentary capability data.To ensure we only expose fully implemented methods with corresponding capability data, we check each outcome before reporting that an attribute can be supported.
Checking for
lwmi_is_attr_01_supportedduring remove is not done to ensure that we don't attempt to call cd01 or send WMI events if one of the interfaces being removed was the cause of the driver unloading.Reviewed-by Mark Pearson <[email protected]>Reported-by Kurt Borja <[email protected]>Signed-off-by Derek J. Clark <[email protected]>---
v5:
- Move cv/cd_mode_id refrences from path 3/4.
- Add missing import forARRAY_SIZE.
- Makelwmi_is_attr_01_supportedreturn bool instead of u32.
- Various formatting fixes.
v4:
- Use for loop instead of backtrace gotos for checking if an attribute is supported.
- Add include fordev_printk.
- Wrapdev_dbginlwmi_is_attr_01_supportedearlier.
- Don't use symmetric cleanup of attributes in error states.--- drivers/platform/x86/lenovo/wmi-other.c | 87 ++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 3 deletions(-)drivers/platform/x86/lenovo/wmi-other.c +22
-1@@ -27,10 +27,12 @@*/ #include <linux/acpi.h> +#include <linux/array_size.h> #include <linux/cleanup.h> #include <linux/component.h> #include <linux/container_of.h> #include <linux/device.h> +#include <linux/dev_printk.h> #include <linux/export.h> #include <linux/gfp_types.h> #include <linux/hwmon.h> @@ -546,6 +548,8 @@ struct tunable_attr_01 {u8 feature_id;u8 device_id;u8 type_id; +u8 cd_mode_id;/* mode arg for searching capdata */ +u8 cv_mode_id;/* mode arg for set/get current_value */ };static struct tunable_attr_01 ppt_pl1_spl = {@@ -778,7 +782,7 @@ static ssize_t attr_current_value_store(struct kobject *kobj,return -EBUSY ; args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, - mode, tunable_attr->type_id); + tunable_attr->cd_mode_id, tunable_attr->type_id); ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata);if (ret)@@ -831,6 +835,10 @@ static ssize_t attr_current_value_show(struct kobject *kobj,if (ret)return ret; +/* If "no-mode" is the supported mode, ensure we never send current mode */ +if (tunable_attr->cv_mode_id ==LWMI_GZ_THERMAL_MODE_NONE ) + mode = tunable_attr->cv_mode_id; + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, mode, tunable_attr->type_id);@@ -843,6 +851,77 @@ static ssize_t attr_current_value_show(struct kobject *kobj,return sysfs_emit (buf,"%d\n" , retval); } +/** +* lwmi_attr_01_is_supported() - Determine if the given attribute is supported. +* @tunable_attr: The attribute to verify. +* +* First check if the attribute has a corresponding capdata01 table in the cd01 +* module under the "custom" mode (0xff). If that is not present then check if +* there is a corresponding "no-mode" (0x00) entry. If either of those passes, +* check capdata->supported for values > 0. If capdata is available, attempt to +* determine the set/get mode for the current value property using a similar +* pattern. If the value returned by either custom or no-mode is 0, or we get +* an error, we assume that mode is not supported. If any of the above checks +* fail then the attribute is not fully supported. +*
drivers/platform/x86/lenovo/wmi-other.c static ssize_t attr_current_value_show(struct kobject *kobj, · line 876
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+* The probed cd_mode_id/cv_mode_id are stored on the tunable_attr for later +* reference. +* +* Return: bool. +*/ +static bool lwmi_attr_01_is_supported (struct tunable_attr_01 *tunable_attr) +{ +u8 modes[2 ] = {LWMI_GZ_THERMAL_MODE_CUSTOM ,LWMI_GZ_THERMAL_MODE_NONE }; +struct lwmi_om_priv *priv =dev_get_drvdata (tunable_attr->dev); +struct wmi_method_args_32 args;
See my reply to the previous patch, i.e., zero-initialize `args'.
Quoted 31 lines
drivers/platform/x86/lenovo/wmi-other.c +31
-0+bool cd_mode_found = false; +bool cv_mode_found = false; +struct capdata01 capdata; +int retval, ret, i; + +/* Determine tunable_attr->cd_mode_id*/ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + modes[i], tunable_attr->type_id); + + ret =lwmi_cd01_get_data (priv->cd01_list, args.arg0, &capdata); +if (ret || !capdata.supported) +continue ; + tunable_attr->cd_mode_id = modes[i]; + cd_mode_found = true; +break ; + } + +if (!cd_mode_found) +return cd_mode_found; + +/* Determine tunable_attr->cv_mode_id, returns 1 if supported*/ +for (i =0 ; i <ARRAY_SIZE (modes); i++) { + args.arg0 =lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + modes[i], tunable_attr->type_id); + + ret =lwmi_dev_evaluate_int (priv->wdev,0x0 ,LWMI_FEATURE_VALUE_GET , + (unsigned char *)&args,sizeof (args), + &retval); +if (ret || !retval) +continue ;
drivers/platform/x86/lenovo/wmi-other.c static ssize_t attr_current_value_show(struct kobject *kobj, · line 917
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+ tunable_attr->cv_mode_id = modes[i]; + cv_mode_found = true; +break ; + } + +if (!cv_mode_found) +return cv_mode_found; + + dev_dbg(tunable_attr->dev, + "cd_mode_id: %#10x, cv_mode_id: %#10x attribute support level: %#10x\n",
^
A comma is missing here.
Also, the format specifier should be `%#010x', otherwise the padding will be whitespace instead of 0. Sorry for the mistake in my reply to v4.
Thanks,
Rong
Quoted 27 lines
drivers/platform/x86/lenovo/wmi-other.c +11
-2+lwmi_attr_id (tunable_attr->device_id, tunable_attr->feature_id, + tunable_attr->cd_mode_id, tunable_attr->type_id), + args.arg0, capdata.supported); + +return capdata.supported >0 ? true : false; +} +/* Lenovo WMI Other Mode Attribute macros */ #define __LWMI_ATTR_RO (_func, _name) \ { \@@ -966,12 +1045,14 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv) }for (i =0 ; i <ARRAY_SIZE (cd01_attr_groups) -1 ; i++) { + cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; +if (!lwmi_attr_01_is_supported (cd01_attr_groups[i].tunable_attr)) +continue ; + err =sysfs_create_group (&priv->fw_attr_kset->kobj, cd01_attr_groups[i].attr_group);if (err) goto err_remove_groups; - - cd01_attr_groups[i].tunable_attr->dev = &priv->wdev->dev; }return 0 ;
Derek J. Clark
maintainerPATCH v5 5/8 platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes
In reply to Derek J. ClarkUse an enum for all device ID's and CPU attribute feature ID's, add missing CPU attributes.
---
v4:
- Align type ID defines.
- Align CPU feature enum values.
- remove cpu_oc_stat from Documentation.
v3:
- Remove cpu_oc_stat.
--- .../wmi/devices/lenovo-wmi-other.rst | 9 ++ drivers/platform/x86/lenovo/wmi-capdata.h | 5 +- drivers/platform/x86/lenovo/wmi-other.c | 101 +++++++++++++++++- 3 files changed, 109 insertions(+), 6 deletions(-)
Documentation/wmi/devices/lenovo-wmi-other.rst +9 -0
@@ -68,9 +68,18 @@ Each attribute has the following properties: - type The following firmware-attributes are implemented: + - cpu_temp: CPU Thermal Load Limit + - ppt_cpu_cl: CPU Cross Loading Power Limit + - ppt_pl1_apu_spl: Platform Profile Tracking APU Sustained Power Limit - ppt_pl1_spl: Platform Profile Tracking Sustained Power Limit + - ppt_pl1_spl_cl: Platform Profile Tracking Cross Loading Sustained Power Limit + - ppt_pl1_tau: Exceed Duration for Platform Profile Tracking Sustained Power Limit - ppt_pl2_sppt: Platform Profile Tracking Slow Package Power Tracking + - ppt_pl2_sppt_cl: Platform Profile Tracking Cross Loading Slow Package Tracking - ppt_pl3_fppt: Platform Profile Tracking Fast Package Power Tracking + - ppt_pl3_fppt_cl: Platform Profile Tracking Cross Loading Fast Package Power Tracking + - ppt_pl4_ipl: Platform Profile Trakcing Instantaneous Power Limit + - ppt_pl4_ipl_cl: Platform Profile Tracking Cross Loading Instantaneous Power Limit LENOVO_FAN_TEST_DATA -------------------------
drivers/platform/x86/lenovo/wmi-capdata.h +4 -1
@@ -17,7 +17,10 @@#define LWMI_ATTR_MODE_ID_MASK GENMASK(15, 8)#define LWMI_ATTR_TYPE_ID_MASK GENMASK(7, 0) -#define LWMI_DEVICE_ID_FAN 0x04 +enum lwmi_device_id { +LWMI_DEVICE_ID_CPU =0x01 , +LWMI_DEVICE_ID_FAN =0x04 , +};#define LWMI_TYPE_ID_NONE 0x00
drivers/platform/x86/lenovo/wmi-other.c +96 -5
151 lines not on this page · raw message
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 6/8 platform/x86: lenovo-wmi-other: Add GPU tunable attributes
In reply to Derek J. ClarkUse an enum for all GPU attribute feature ID's and add GPU attributes.
---
v4:
- Align CPU feature enum values.
- Remove gpu_oc_stat from Documentation.
v3:
- Remove gpu_oc_stat.
--- .../wmi/devices/lenovo-wmi-other.rst | 10 ++ drivers/platform/x86/lenovo/wmi-capdata.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 105 ++++++++++++++++++ 3 files changed, 116 insertions(+)
Documentation/wmi/devices/lenovo-wmi-other.rst +10 -0
@@ -69,6 +69,16 @@ Each attribute has the following properties: The following firmware-attributes are implemented: - cpu_temp: CPU Thermal Load Limit + - dgpu_boost_clk: Dedicated GPU Boost Clock + - dgpu_enable: Dedicated GPU Enabled Status + - gpu_didvid: GPU Device Identifier and Vendor Identifier + - gpu_mode: GPU Mode by Power Limit + - gpu_nv_ac_offset: Nvidia GPU AC Total Processing Power Baseline Offset + - gpu_nv_bpl: Nvidia GPU Base Power Limit + - gpu_nv_cpu_boost: Nvidia GPU to CPU Dynamic Boost Limit + - gpu_nv_ctgp: Nvidia GPU Configurable Total Graphics Power + - gpu_nv_ppab: Nvidia GPU Power Performance Aware Boost Limit + - gpu_temp: GPU Thermal Load Limit - ppt_cpu_cl: CPU Cross Loading Power Limit - ppt_pl1_apu_spl: Platform Profile Tracking APU Sustained Power Limit - ppt_pl1_spl: Platform Profile Tracking Sustained Power Limit
drivers/platform/x86/lenovo/wmi-capdata.h +1 -0
@@ -19,6 +19,7 @@enum lwmi_device_id {LWMI_DEVICE_ID_CPU =0x01 , +LWMI_DEVICE_ID_GPU =0x02 ,LWMI_DEVICE_ID_FAN =0x04 , };
drivers/platform/x86/lenovo/wmi-other.c +105 -0
132 lines not on this page · raw message
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 7/8 platform-x86: lenovo-wmi-other: Rename LWMI_OM_FW_ATTR_BASE_PATH
In reply to Derek J. ClarkIn the next patch a power supply extension is added which requires a name attribute. Instead of creating another const macro with the same information, rename LWMI_OM_FW_ATTR_BASE_PATH to LWMI_OM_SYSFS_NAME.
--- drivers/platform/x86/lenovo/wmi-other.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/platform/x86/lenovo/wmi-other.c +2 -3
@@ -96,7 +96,7 @@ enum lwmi_feature_id_gpu {lwmi_attr_id (LWMI_DEVICE_ID_FAN ,LWMI_FEATURE_ID_FAN_RPM , \ LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x)) -#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other" +#define LWMI_OM_SYSFS_NAME "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"static BLOCKING_NOTIFIER_HEAD (om_chain_head);
@@ -1226,8 +1226,7 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv) priv->fw_attr_dev =device_create (&firmware_attributes_class,NULL ,MKDEV (0 ,0 ),NULL ,"%s-%u" , -LWMI_OM_FW_ATTR_BASE_PATH , - priv->ida_id); +LWMI_OM_SYSFS_NAME , priv->ida_id);if (IS_ERR (priv->fw_attr_dev)) { err =PTR_ERR (priv->fw_attr_dev); goto err_free_ida;
Signature · 1 line
2.53.0
Derek J. Clark
maintainerPATCH v5 8/8 platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
In reply to Derek J. ClarkAdd charge-type power supply extension for devices that support WMI based charge enable/disable.
Lenovo Legion devices that implement WMI function and capdata ID 0x03010001 in their BIOS are able to enable or disable charging at 80% through the lenovo-wmi-other interface. Add a charge_type power supply extension to expose this capability to the sysfs.
The ideapad_laptop driver can also provide the charge_type attribute. To avoid conflicts between the drivers, get the acpi_handle and do the same check that ideapad_laptop does when it enables the feature. If the feature is supported in ideapad_laptop, abort adding the extension from lenovo-wmi-other. The ACPI method is more reliable when both are present, from my testing, so we can prefer that implementation and do not need to worry about de-conflicting from inside that driver. A new module parameter, force_load_psy_ext, is provided to bypass this ACPI check, if desired.
---
v5:
- Use switch statement instead of if for battery charge state set/get.
- use force_load_psy_ext to skip all ACPI interactions.
- Various formatting fixes.
v4:
- Remove unused defines.
- Disambiguate charging defines by renaming them to be more consistent with the kernel modes they represent.
- Add module parameter to ignore ACPI checks.
- Don't fail if the ACPI handle isn't found, skip the ACPI check instead.
--- drivers/platform/x86/lenovo/Kconfig | 1 + drivers/platform/x86/lenovo/wmi-capdata.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 250 +++++++++++++++++++++- 3 files changed, 251 insertions(+), 1 deletion(-)
drivers/platform/x86/lenovo/Kconfig +1 -0
@@ -263,6 +263,7 @@ config LENOVO_WMI_GAMEZONE config LENOVO_WMI_TUNING tristate "Lenovo Other Mode WMI Driver" depends on ACPI_WMI + depends on ACPI_BATTERY select HWMON select FW_ATTR_CLASS select LENOVO_WMI_CAPDATA
drivers/platform/x86/lenovo/wmi-capdata.h +1 -0
@@ -20,6 +20,7 @@enum lwmi_device_id {LWMI_DEVICE_ID_CPU =0x01 ,LWMI_DEVICE_ID_GPU =0x02 , +LWMI_DEVICE_ID_PSU =0x03 ,LWMI_DEVICE_ID_FAN =0x04 , };
drivers/platform/x86/lenovo/wmi-other.c +249 -1
295 lines not on this page · raw message
Signature · 1 line
2.53.0
kernel test robot
build botRe: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
kernel test robot noticed the following build errors:
Hi Derek,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc5 next-20260324]
[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/Derek-J-Clark/platform-x86-lenovo-wmi-other-Move-LWMI_FAN_DIV/20260325-070851 base: linus/master patch link: https://lore.kernel.org/r/20260324221032.1333636-9-derekjohn.clark%40gmail.com patch subject: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting config: i386-buildonly-randconfig-006-20260325 (https://download.01.org/0day-ci/archive/20260325/[email protected]/config) compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260325/[email protected]/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 <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>, old ones prefixed by <<):
>> ERROR: modpost: "lwmi_cd_match_add_all" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! >> ERROR: modpost: "lwmi_attr_id" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! >> ERROR: modpost: "lwmi_cd00_get_data" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! ERROR: modpost: "devm_battery_hook_register" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! >> ERROR: modpost: "firmware_attributes_class" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! >> ERROR: modpost: "lwmi_cd01_get_data" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined! >> ERROR: modpost: "lwmi_cd_fan_get_data" [drivers/platform/x86/lenovo/lenovo-wmi-other.ko] undefined!
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for LENOVO_WMI_TUNING Depends on [n]: X86_PLATFORM_DEVICES [=y] && ACPI_WMI [=y] && ACPI_BATTERY [=n] Selected by [m]:
- LENOVO_WMI_GAMEZONE [=m] && X86_PLATFORM_DEVICES [=y] && ACPI_WMI [=y] && DMI [=y]
Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Re: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
In reply to Derek J. ClarkHi Derek,
Quoted 135 lines · Derek J. Clark
Add charge-type power supply extension for devices that support WMI based charge enable/disable.
Lenovo Legion devices that implement WMI function and capdata ID
0x03010001in their BIOS are able to enable or disable charging at 80% through the lenovo-wmi-other interface. Add acharge_typepower supply extension to expose this capability to the sysfs.The
ideapad_laptopdriver can also provide thecharge_typeattribute. To avoid conflicts between the drivers, get theacpi_handleand do the same check thatideapad_laptopdoes when it enables the feature. If the feature is supported inideapad_laptop, abort adding the extension from lenovo-wmi-other. The ACPI method is more reliable when both are present, from my testing, so we can prefer that implementation and do not need to worry about de-conflicting from inside that driver. A new module parameter,force_load_psy_ext, is provided to bypass this ACPI check, if desired.Reviewed-by Mark Pearson <[email protected]>Signed-off-by Derek J. Clark <[email protected]>---
v5:
- Use switch statement instead of if for battery charge state set/get.
- useforce_load_psy_extto skip all ACPI interactions.
- Various formatting fixes.
v4:
- Remove unused defines.
- Disambiguate charging defines by renaming them to be more consistent with the kernel modes they represent.
- Add module parameter to ignore ACPI checks.
- Don't fail if the ACPI handle isn't found, skip the ACPI check instead.--- drivers/platform/x86/lenovo/Kconfig | 1 + drivers/platform/x86/lenovo/wmi-capdata.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 250 +++++++++++++++++++++- 3 files changed, 251 insertions(+), 1 deletion(-)drivers/platform/x86/lenovo/Kconfig +1
-0@@ -263,6 +263,7 @@ config LENOVO_WMI_GAMEZONE config LENOVO_WMI_TUNING tristate "Lenovo Other Mode WMI Driver" depends on ACPI_WMI + depends on ACPI_BATTERY select HWMON select FW_ATTR_CLASS select LENOVO_WMI_CAPDATAdrivers/platform/x86/lenovo/wmi-capdata.h +1
-0@@ -20,6 +20,7 @@enum lwmi_device_id {LWMI_DEVICE_ID_CPU =0x01 ,LWMI_DEVICE_ID_GPU =0x02 , +LWMI_DEVICE_ID_PSU =0x03 ,LWMI_DEVICE_ID_FAN =0x04 , };drivers/platform/x86/lenovo/wmi-other.c +27
-1@@ -43,9 +43,12 @@#include <linux/module.h> #include <linux/notifier.h> #include <linux/platform_profile.h> +#include <linux/power_supply.h> #include <linux/types.h> #include <linux/wmi.h> +#include <acpi/battery.h> +#include "wmi-capdata.h" #include "wmi-events.h" #include "wmi-gamezone.h" @@ -79,9 +82,11 @@ enum lwmi_feature_id_gpu { LWMI_FEATURE_ID_GPU_NV_CPU_BOOST = 0x0b, }; -#define LWMI_FEATURE_ID_FAN_RPM 0x03 +#define LWMI_FEATURE_ID_FAN_RPM 0x03 +#define LWMI_FEATURE_ID_PSU_CHARGE_TYPE 0x01#define LWMI_TYPE_ID_CROSSLOAD 0x01 +#define LWMI_TYPE_ID_PSU_AC 0x01#define LWMI_FEATURE_VALUE_GET 17#define LWMI_FEATURE_VALUE_SET 18@@ -92,10 +97,17 @@ enum lwmi_feature_id_gpu {#define LWMI_FAN_DIV 100 +#define LWMI_CHARGE_TYPE_STANDARD 0x00 +#define LWMI_CHARGE_TYPE_LONGLIFE 0x01 +#define LWMI_ATTR_ID_FAN_RPM (x) \ lwmi_attr_id(LWMI_DEVICE_ID_FAN, LWMI_FEATURE_ID_FAN_RPM, \ LWMI_GZ_THERMAL_MODE_NONE, LWMI_FAN_ID(x)) +#define LWMI_ATTR_ID_PSU (feat, type) \ + lwmi_attr_id(LWMI_DEVICE_ID_PSU, feat, \ + LWMI_GZ_THERMAL_MODE_NONE, type) +#define LWMI_OM_SYSFS_NAME "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"@@ -137,6 +149,8 @@ struct lwmi_om_priv { bool capdata00_collected : 1; bool capdata_fan_collected : 1; } fan_flags; + +struct acpi_battery_hook battery_hook; };/* @@ -561,6 +575,239 @@ static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list *lwmi_om_hwmon_add (priv); } +/* ======== Power Supply Extension (component: lenovo-wmi-capdata 00) ======== */ + +/** +* lwmi_psy_ext_get_prop() - Get a power_supply_ext property +* @ps: The battery that was extended +* @ext: The extension +* @ext_data: Pointer the lwmi_om_priv drvdata +* @prop: The property to read +* @val: The value to return +* +* Writes the given value to the power_supply_ext property +*
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 599
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+* Return: 0 on success, or an error +*/ +static int lwmi_psy_ext_get_prop (struct power_supply *ps, +const struct power_supply_ext *ext, +void *ext_data, +enum power_supply_property prop, +union power_supply_propval *val) +{ +struct lwmi_om_priv *priv = ext_data; +struct wmi_method_args_32 args;
Zero-initialize `args'. See my previous reply.
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 611
Quoted 12 lines
drivers/platform/x86/lenovo/wmi-other.c +12
-0+u32 retval; +int ret; + + args.arg0 =LWMI_ATTR_ID_PSU (LWMI_FEATURE_ID_PSU_CHARGE_TYPE ,LWMI_TYPE_ID_PSU_AC ); + + ret =lwmi_dev_evaluate_int (priv->wdev,0x0 ,LWMI_FEATURE_VALUE_GET , + (unsigned char *)&args,sizeof (args), + &retval); +if (ret) +return ret; + +dev_dbg (&priv->wdev->dev,"Got return value %x for property %#x\n" , retval, prop);
Both should be `%#x'.
Quoted 42 lines
drivers/platform/x86/lenovo/wmi-other.c +42
-0+ +switch (retval) { +case LWMI_CHARGE_TYPE_LONGLIFE : + val->intval =POWER_SUPPLY_CHARGE_TYPE_LONGLIFE ; +break ; +case LWMI_CHARGE_TYPE_STANDARD : + val->intval =POWER_SUPPLY_CHARGE_TYPE_STANDARD ; +break ; +default : +dev_err (&priv->wdev->dev,"Got invalid charge value: %#x\n" , retval); +return -EINVAL ; + } + +return 0 ; +} + +/** +* lwmi_psy_ext_set_prop() - Set a power_supply_ext property +* @ps: The battery that was extended +* @ext: The extension +* @ext_data: Pointer the lwmi_om_priv drvdata +* @prop: The property to write +* @val: The value to write +* +* Writes the given value to the power_supply_ext property +* +* Return: 0 on success, or an error +*/ +static int lwmi_psy_ext_set_prop (struct power_supply *ps, +const struct power_supply_ext *ext, +void *ext_data, +enum power_supply_property prop, +const union power_supply_propval *val) +{ +struct lwmi_om_priv *priv = ext_data; +struct wmi_method_args_32 args; + + args.arg0 =LWMI_ATTR_ID_PSU (LWMI_FEATURE_ID_PSU_CHARGE_TYPE ,LWMI_TYPE_ID_PSU_AC ); +switch (val->intval) { +case POWER_SUPPLY_CHARGE_TYPE_LONGLIFE : + args.arg1 =LWMI_CHARGE_TYPE_LONGLIFE ; +break ;
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 663
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+case POWER_SUPPLY_CHARGE_TYPE_STANDARD : + args.arg1 =LWMI_CHARGE_TYPE_STANDARD ; +break ; +default : +dev_err (&priv->wdev->dev,"Got invalid charge value: %#x\n" , val->intval); +return -EINVAL ; + } + +dev_dbg (&priv->wdev->dev,"Attempting to set %#10x for property %#x to %#x\n" , + args.arg0, prop, args.arg1);
%#010x
Quoted 22 lines
drivers/platform/x86/lenovo/wmi-other.c +22
-0+ +return lwmi_dev_evaluate_int (priv->wdev,0x0 ,LWMI_FEATURE_VALUE_SET , + (unsigned char *)&args,sizeof (args),NULL ); +} + +/** +* lwmi_psy_prop_is_writeable() - Determine if the property is supported +* @ps: The battery that was extended +* @ext: The extension +* @ext_data: Pointer the lwmi_om_priv drvdata +* @prop: The property to check +* +* Checks capdata 00 to determine if the property is supported. +* +* Return: Support level, or false +*/ +static int lwmi_psy_prop_is_writeable (struct power_supply *ps, +const struct power_supply_ext *ext, +void *ext_data, +enum power_supply_property prop) +{ +struct lwmi_om_priv *priv = ext_data;
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 695
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+struct capdata00 capdata; +u32 attribute_id =LWMI_ATTR_ID_PSU (LWMI_FEATURE_ID_PSU_CHARGE_TYPE ,LWMI_TYPE_ID_PSU_AC ); +int ret; + + ret =lwmi_cd00_get_data (priv->cd00_list, attribute_id, &capdata); +if (ret) +return false; + +dev_dbg (&priv->wdev->dev,"Battery charge mode (%#10x) support level: %#x\n" , + attribute_id, capdata.supported);
%#010x
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 697
Quoted 2 lines
drivers/platform/x86/lenovo/wmi-other.c +2
-0+ +return capdata.supported;
This casts u32 into a *signed* int. I'd suggest:
return !!(capdata.supported & LWMI_SUPP_SET);
LWMI_SUPP_VALID and LWMI_SUPP_GET should also be checked before registering the power supply extension. See below.
Quoted 74 lines
drivers/platform/x86/lenovo/wmi-other.c +74
-0+} + +static const enum power_supply_property lwmi_psy_ext_props[] = { +POWER_SUPPLY_PROP_CHARGE_TYPES , +}; + +static const struct power_supply_ext lwmi_psy_ext = { + .name =LWMI_OM_SYSFS_NAME , + .properties = lwmi_psy_ext_props, + .num_properties =ARRAY_SIZE (lwmi_psy_ext_props), + .charge_types = (BIT (POWER_SUPPLY_CHARGE_TYPE_STANDARD ) | +BIT (POWER_SUPPLY_CHARGE_TYPE_LONGLIFE )), + .get_property = lwmi_psy_ext_get_prop, + .set_property = lwmi_psy_ext_set_prop, + .property_is_writeable = lwmi_psy_prop_is_writeable, +}; + +/** +* lwmi_add_battery() - Connect the power_supply_ext +* @battery: The battery to extend +* @hook: The driver hook used to extend the battery +* +* Return: 0 on success, or an error. +*/ +static int lwmi_add_battery (struct power_supply *battery,struct acpi_battery_hook *hook) +{ + struct lwmi_om_priv *priv = container_of(hook, struct lwmi_om_priv, battery_hook); + +return power_supply_register_extension (battery, &lwmi_psy_ext, &priv->wdev->dev, priv); +} + +/** +* lwmi_remove_battery() - Disconnect the power_supply_ext +* @battery: The battery that was extended +* @hook: The driver hook used to extend the battery +* +* Return: 0 on success, or an error. +*/ +static int lwmi_remove_battery (struct power_supply *battery,struct acpi_battery_hook *hook) +{ +power_supply_unregister_extension (battery, &lwmi_psy_ext); +return 0 ; +} + +/** +* lwmi_acpi_match() - Attempts to return the ideapad acpi handle +* @handle: The ACPI handle that manages battery charging +* @lvl: Unused +* @context: Void pointer to the acpi_handle object to return +* @retval: Unused +* +* Checks if the ideapad_laptop driver is going to manage charge_type first, +* then if not, hooks the battery to our WMI methods. +* +* Return: AE_CTRL_TERMINATE if found, AE_OK if not found. +*/ +static acpi_status lwmi_acpi_match (acpi_handle handle,u32 lvl, +void *context,void **retval) +{ +acpi_handle *ahand = context; + +if (!handle) +return AE_OK ; + + *ahand = handle; + +return AE_CTRL_TERMINATE ; +} + +static bool force_load_psy_ext; +module_param (force_load_psy_ext, bool,0444 ); +MODULE_PARM_DESC (force_load_psy_ext, +"This option will skip checking if the ideapad_laptop driver will conflict " + "with adding an extension to set the battery charge type. It is recommended "
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 781
Quoted 10 lines
drivers/platform/x86/lenovo/wmi-other.c +10
-0+ "to blacklist the ideapad driver before using this option."); + +/** +* lwmi_om_ps_ext_init() - Hooks power supply extension to device battery +* @priv: Driver private data +* +* Checks if the ideapad_laptop driver is going to manage charge_type first, +* then if not, hooks the battery to our WMI methods. +*/ +static void lwmi_om_ps_ext_init (struct lwmi_om_priv *priv)
Nitpick: rename it to lwmi_om_psy_ext_init (note the "y") to make naming consistent.
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 789
Quoted 8 lines
drivers/platform/x86/lenovo/wmi-other.c +8
-0+{ +static const char *const ideapad_hid ="VPC2004" ; +acpi_handle handle =NULL ; +int ret; + +/* Deconflict ideapad_laptop driver */ +if (force_load_psy_ext) + goto load_psy_ext;
Query capdata00 and check against (capdata.supported & LWMI_SUPP_VALID) && (capdata.supported & LWMI_SUPP_GET) before continuing. If it's unsupported or unreadable, no need to register a bogus power supply extension. force_load_psy_ext should be able to override this too.
drivers/platform/x86/lenovo/wmi-other.c static void lwmi_om_fan_info_collect_cd_fan(struct device *dev, struct cd_list * · line 796
Quoted 7 lines
drivers/platform/x86/lenovo/wmi-other.c +7
-0+ + ret =acpi_get_devices (ideapad_hid, lwmi_acpi_match, &handle,NULL ); +if (ret) +return ; + +if (handle &&acpi_has_method (handle,"GBMD" ) &&acpi_has_method (handle,"SBMC" )) { +dev_dbg (&priv->wdev->dev,"ideapad_laptop driver manages battery for device.\n" );
Drop the period at the end of the string.
Thanks,
Rong
Quoted 25 lines
drivers/platform/x86/lenovo/wmi-other.c +15
-0+return ; + } + +load_psy_ext: +/* Add battery hooks */ + priv->battery_hook.add_battery = lwmi_add_battery; + priv->battery_hook.remove_battery = lwmi_remove_battery; + priv->battery_hook.name ="Lenovo WMI Other Battery Extension" ; + + ret =devm_battery_hook_register (&priv->wdev->dev, &priv->battery_hook); +if (ret) +dev_err (&priv->wdev->dev,"Error during battery hook: %i\n" , ret); +} +/* ======== fw_attributes (component: lenovo-wmi-capdata 01) ======== */ struct tunable_attr_01 {@@ -1318,6 +1565,7 @@ static int lwmi_om_master_bind(struct device *dev)return -ENODEV ;lwmi_om_fan_info_collect_cd00 (priv); +lwmi_om_ps_ext_init (priv);return lwmi_om_fw_attr_add (priv); }
kernel test robot
build botRe: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
In reply to Derek J. Clarkkernel test robot noticed the following build errors:
Hi Derek,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc5 next-20260324]
[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/Derek-J-Clark/platform-x86-lenovo-wmi-other-Move-LWMI_FAN_DIV/20260325-070851 base: linus/master patch link: https://lore.kernel.org/r/20260324221032.1333636-9-derekjohn.clark%40gmail.com patch subject: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting config: x86_64-randconfig-005-20260325 (https://download.01.org/0day-ci/archive/20260326/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260326/[email protected]/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 <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
All errors (new ones prefixed by >>):
ld: vmlinux.o: in function `lwmi_om_fan_get_set':
>> drivers/platform/x86/lenovo/wmi-other.c:206:(.text+0x1b74542): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `lwmi_attr_01_is_supported': drivers/platform/x86/lenovo/wmi-other.c:1267:(.text+0x1b74fdf): undefined reference to `lwmi_attr_id' >> ld: drivers/platform/x86/lenovo/wmi-other.c:1270:(.text+0x1b75013): undefined reference to `lwmi_cd01_get_data' >> ld: drivers/platform/x86/lenovo/wmi-other.c:1283:(.text+0x1b7515b): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1299:(.text+0x1b752f4): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd_fan': >> drivers/platform/x86/lenovo/wmi-other.c:565:(.text+0x1b75ca3): undefined reference to `lwmi_cd_fan_get_data' ld: vmlinux.o: in function `lwmi_psy_prop_is_writeable': drivers/platform/x86/lenovo/wmi-other.c:687:(.text+0x1b75e2f): undefined reference to `lwmi_attr_id' >> ld: drivers/platform/x86/lenovo/wmi-other.c:690:(.text+0x1b75e5a): undefined reference to `lwmi_cd00_get_data' ld: vmlinux.o: in function `lwmi_psy_ext_set_prop': drivers/platform/x86/lenovo/wmi-other.c:649:(.text+0x1b75f9b): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `lwmi_psy_ext_get_prop': drivers/platform/x86/lenovo/wmi-other.c:603:(.text+0x1b761aa): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `lwmi_other_probe': >> drivers/platform/x86/lenovo/wmi-other.c:1612:(.text+0x1b764eb): undefined reference to `lwmi_cd_match_add_all' ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd00': drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b7680f): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b76838): undefined reference to `lwmi_cd00_get_data' ld: vmlinux.o: in function `lwmi_om_ps_ext_init': >> drivers/platform/x86/lenovo/wmi-other.c:806:(.text+0x1b76a57): undefined reference to `devm_battery_hook_register' ld: vmlinux.o: in function `lwmi_om_fw_attr_add': >> drivers/platform/x86/lenovo/wmi-other.c:1474:(.text+0x1b76afa): undefined reference to `firmware_attributes_class'
ld: vmlinux.o: in function `attr_current_value_show':
drivers/platform/x86/lenovo/wmi-other.c:1225:(.text+0x1b77015): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `attr_current_value_store':
drivers/platform/x86/lenovo/wmi-other.c:1165:(.text+0x1b776e2): undefined reference to `lwmi_attr_id'
ld: drivers/platform/x86/lenovo/wmi-other.c:1168:(.text+0x1b7771c): undefined reference to `lwmi_cd01_get_data'
ld: drivers/platform/x86/lenovo/wmi-other.c:1179:(.text+0x1b7781e): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `attr_capdata01_show':
drivers/platform/x86/lenovo/wmi-other.c:1099:(.text+0x1b77e38): undefined reference to `lwmi_attr_id'
ld: drivers/platform/x86/lenovo/wmi-other.c:1102:(.text+0x1b77e67): undefined reference to `lwmi_cd01_get_data'
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for LENOVO_WMI_TUNING Depends on [m]: X86_PLATFORM_DEVICES [=y] && ACPI_WMI [=y] && ACPI_BATTERY [=m] Selected by [y]:
- LENOVO_WMI_GAMEZONE [=y] && X86_PLATFORM_DEVICES [=y] && ACPI_WMI [=y] && DMI [=y]
vim +206 drivers/platform/x86/lenovo/wmi-other.c
51ed34282f63fa Rong Zhang 2026-01-21 186
51ed34282f63fa Rong Zhang 2026-01-21 187 /**
51ed34282f63fa Rong Zhang 2026-01-21 188 * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan
51ed34282f63fa Rong Zhang 2026-01-21 189 * @priv: Driver private data structure
51ed34282f63fa Rong Zhang 2026-01-21 190 * @channel: Fan channel index (0-based)
51ed34282f63fa Rong Zhang 2026-01-21 191 * @val: Pointer to value (input for set, output for get)
51ed34282f63fa Rong Zhang 2026-01-21 192 * @set: True to set value, false to get value
51ed34282f63fa Rong Zhang 2026-01-21 193 *
51ed34282f63fa Rong Zhang 2026-01-21 194 * Communicates with WMI interface to either retrieve current fan RPM
51ed34282f63fa Rong Zhang 2026-01-21 195 * or set target fan RPM.
51ed34282f63fa Rong Zhang 2026-01-21 196 *
51ed34282f63fa Rong Zhang 2026-01-21 197 * Return: 0 on success, or an error code.
51ed34282f63fa Rong Zhang 2026-01-21 198 */
51ed34282f63fa Rong Zhang 2026-01-21 199 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set)
51ed34282f63fa Rong Zhang 2026-01-21 200 {
51ed34282f63fa Rong Zhang 2026-01-21 201 struct wmi_method_args_32 args;
51ed34282f63fa Rong Zhang 2026-01-21 202 u32 method_id, retval;
51ed34282f63fa Rong Zhang 2026-01-21 203 int err;
51ed34282f63fa Rong Zhang 2026-01-21 204
51ed34282f63fa Rong Zhang 2026-01-21 205 method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET;
51ed34282f63fa Rong Zhang 2026-01-21 @206 args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel);
51ed34282f63fa Rong Zhang 2026-01-21 207 args.arg1 = set ? *val : 0;
51ed34282f63fa Rong Zhang 2026-01-21 208
51ed34282f63fa Rong Zhang 2026-01-21 209 err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id,
51ed34282f63fa Rong Zhang 2026-01-21 210 (unsigned char *)&args, sizeof(args), &retval);
51ed34282f63fa Rong Zhang 2026-01-21 211 if (err)
51ed34282f63fa Rong Zhang 2026-01-21 212 return err;
51ed34282f63fa Rong Zhang 2026-01-21 213
51ed34282f63fa Rong Zhang 2026-01-21 214 if (!set) {
51ed34282f63fa Rong Zhang 2026-01-21 215 *val = retval;
51ed34282f63fa Rong Zhang 2026-01-21 216 return 0;
51ed34282f63fa Rong Zhang 2026-01-21 217 }
51ed34282f63fa Rong Zhang 2026-01-21 218
51ed34282f63fa Rong Zhang 2026-01-21 219 /*
51ed34282f63fa Rong Zhang 2026-01-21 220 * It seems that 0 means "no error" and 1 means "done". Apparently
51ed34282f63fa Rong Zhang 2026-01-21 221 * different firmware teams have different thoughts on indicating
51ed34282f63fa Rong Zhang 2026-01-21 222 * success, so we accepts both.
51ed34282f63fa Rong Zhang 2026-01-21 223 */
51ed34282f63fa Rong Zhang 2026-01-21 224 return (retval == 0 || retval == 1) ? 0 : -EIO;
51ed34282f63fa Rong Zhang 2026-01-21 225 }
51ed34282f63fa Rong Zhang 2026-01-21 226 Signature · 2 lines
0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
Derek John Clark
maintainerRe: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
Quoted 112 lines · kernel test robot
Hi Derek,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc5 next-20260324]
[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/Derek-J-Clark/platform-x86-lenovo-wmi-other-Move-LWMI_FAN_DIV/20260325-070851 base: linus/master patch link: https://lore.kernel.org/r/20260324221032.1333636-9-derekjohn.clark%40gmail.com patch subject: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting config: x86_64-randconfig-005-20260325 (https://download.01.org/0day-ci/archive/20260326/[email protected]/config) compiler: gcc-14 (Debian 14.2.0-19) 14.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260326/[email protected]/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 <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/All errors (new ones prefixed by >>):
ld: vmlinux.o: in function `lwmi_om_fan_get_set':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:206:(.text+0x1b74542): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_attr_01_is_supported':
drivers/platform/x86/lenovo/wmi-other.c:1267:(.text+0x1b74fdf): undefined reference to `lwmi_attr_id'Quoted 2 lines
Quoted 2 lines
ld: drivers/platform/x86/lenovo/wmi-other.c:1270:(.text+0x1b75013): undefined reference to `lwmi_cd01_get_data'
ld: drivers/platform/x86/lenovo/wmi-other.c:1283:(.text+0x1b7515b): undefined reference to `lwmi_attr_id'ld: drivers/platform/x86/lenovo/wmi-other.c:1299:(.text+0x1b752f4): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd_fan':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:565:(.text+0x1b75ca3): undefined reference to `lwmi_cd_fan_get_data'
ld: vmlinux.o: in function `lwmi_psy_prop_is_writeable':
drivers/platform/x86/lenovo/wmi-other.c:687:(.text+0x1b75e2f): undefined reference to `lwmi_attr_id'Quoted 1 line
Quoted 1 line
ld: drivers/platform/x86/lenovo/wmi-other.c:690:(.text+0x1b75e5a): undefined reference to `lwmi_cd00_get_data'
ld: vmlinux.o: in function `lwmi_psy_ext_set_prop':
drivers/platform/x86/lenovo/wmi-other.c:649:(.text+0x1b75f9b): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_psy_ext_get_prop':
drivers/platform/x86/lenovo/wmi-other.c:603:(.text+0x1b761aa): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_other_probe':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1612:(.text+0x1b764eb): undefined reference to `lwmi_cd_match_add_all'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd00':
drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b7680f): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b76838): undefined reference to `lwmi_cd00_get_data' ld: vmlinux.o: in function `lwmi_om_ps_ext_init':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:806:(.text+0x1b76a57): undefined reference to `devm_battery_hook_register'
ld: vmlinux.o: in function `lwmi_om_fw_attr_add':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1474:(.text+0x1b76afa): undefined reference to `firmware_attributes_class'
ld: vmlinux.o: in function `attr_current_value_show':
drivers/platform/x86/lenovo/wmi-other.c:1225:(.text+0x1b77015): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_current_value_store': drivers/platform/x86/lenovo/wmi-other.c:1165:(.text+0x1b776e2): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1168:(.text+0x1b7771c): undefined reference to `lwmi_cd01_get_data' ld: drivers/platform/x86/lenovo/wmi-other.c:1179:(.text+0x1b7781e): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_capdata01_show': drivers/platform/x86/lenovo/wmi-other.c:1099:(.text+0x1b77e38): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1102:(.text+0x1b77e67): undefined reference to `lwmi_cd01_get_data'
Kconfigwarnings: (for reference only)
WARNING: unmet direct dependencies detected forLENOVO_WMI_TUNINGDepends on [m]:X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] &&ACPI_BATTERY[=m] Selected by [y]:
-LENOVO_WMI_GAMEZONE[=y] &&X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] && DMI [=y]vim +206
drivers/platform/x86/lenovo/wmi-other.c51ed34282f63fa Rong Zhang 2026-01-21 186 51ed34282f63fa Rong Zhang 2026-01-21 187 /** 51ed34282f63fa Rong Zhang 2026-01-21 188 * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan 51ed34282f63fa Rong Zhang 2026-01-21 189 * @priv: Driver private data structure 51ed34282f63fa Rong Zhang 2026-01-21 190 * @channel: Fan channel index (0-based) 51ed34282f63fa Rong Zhang 2026-01-21 191 * @val: Pointer to value (input for set, output for get) 51ed34282f63fa Rong Zhang 2026-01-21 192 * @set: True to set value, false to get value 51ed34282f63fa Rong Zhang 2026-01-21 193 * 51ed34282f63fa Rong Zhang 2026-01-21 194 * Communicates with WMI interface to either retrieve current fan RPM 51ed34282f63fa Rong Zhang 2026-01-21 195 * or set target fan RPM. 51ed34282f63fa Rong Zhang 2026-01-21 196 * 51ed34282f63fa Rong Zhang 2026-01-21 197 * Return: 0 on success, or an error code. 51ed34282f63fa Rong Zhang 2026-01-21 198 */ 51ed34282f63fa Rong Zhang 2026-01-21 199 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set) 51ed34282f63fa Rong Zhang 2026-01-21 200 { 51ed34282f63fa Rong Zhang 2026-01-21 201 struct wmi_method_args_32 args; 51ed34282f63fa Rong Zhang 2026-01-21 202 u32 method_id, retval; 51ed34282f63fa Rong Zhang 2026-01-21 203 int err; 51ed34282f63fa Rong Zhang 2026-01-21 204 51ed34282f63fa Rong Zhang 2026-01-21 205 method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET; 51ed34282f63fa Rong Zhang 2026-01-21 @206 args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel); 51ed34282f63fa Rong Zhang 2026-01-21 207 args.arg1 = set ? *val : 0; 51ed34282f63fa Rong Zhang 2026-01-21 208 51ed34282f63fa Rong Zhang 2026-01-21 209 err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id, 51ed34282f63fa Rong Zhang 2026-01-21 210 (unsigned char *)&args, sizeof(args), &retval); 51ed34282f63fa Rong Zhang 2026-01-21 211 if (err) 51ed34282f63fa Rong Zhang 2026-01-21 212 return err; 51ed34282f63fa Rong Zhang 2026-01-21 213 51ed34282f63fa Rong Zhang 2026-01-21 214 if (!set) { 51ed34282f63fa Rong Zhang 2026-01-21 215 *val = retval; 51ed34282f63fa Rong Zhang 2026-01-21 216 return 0; 51ed34282f63fa Rong Zhang 2026-01-21 217 } 51ed34282f63fa Rong Zhang 2026-01-21 218 51ed34282f63fa Rong Zhang 2026-01-21 219 /* 51ed34282f63fa Rong Zhang 2026-01-21 220 * It seems that 0 means "no error" and 1 means "done". Apparently 51ed34282f63fa Rong Zhang 2026-01-21 221 * different firmware teams have different thoughts on indicating 51ed34282f63fa Rong Zhang 2026-01-21 222 * success, so we accepts both. 51ed34282f63fa Rong Zhang 2026-01-21 223 */ 51ed34282f63fa Rong Zhang 2026-01-21 224 return (retval == 0 || retval == 1) ? 0 : -EIO; 51ed34282f63fa Rong Zhang 2026-01-21 225 } 51ed34282f63fa Rong Zhang 2026-01-21 226
Quoted 3 lines
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Can someone explain to me why this is happening? I cannot reproduce these locally with W=1 and/or C=1. I'd prefer to resolve this before submitting a v6.
Thanks,
Derek
Re: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
Hi Derek,
Quoted 12 lines · Derek John Clark
Quoted 11 lines · kernel test robot
Hi Derek,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc5 next-20260324]
[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]
Quoted 5 lines
Quoted 5 lines
url: https://github.com/intel-lab-lkp/linux/commits/Derek-J-Clark/platform-x86-lenovo-wmi-other-Move-LWMI_FAN_DIV/20260325-070851 base: linus/master patch link: https://lore.kernel.org/r/20260324221032.1333636-9-derekjohn.clark%40gmail.com patch subject: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting config: x86_64-randconfig-005-20260325 (https://download.01.org/0day-ci/archive/20260326/[email protected]/config)
CONFIG_DMI=y
CONFIG_HWMON=y
CONFIG_FW_ATTR_CLASS=m
CONFIG_ACPI_BATTERY=m
CONFIG_ACPI_PLATFORM_PROFILE=y
CONFIG_ACPI_WMI=y
CONFIG_LENOVO_WMI_CAPDATA=m
CONFIG_LENOVO_WMI_EVENTS=y
CONFIG_LENOVO_WMI_HELPERS=y
CONFIG_LENOVO_WMI_GAMEZONE=y
CONFIG_LENOVO_WMI_TUNING=y
This isn't a legit config, as CONFIG_LENOVO_WMI_TUNING=y should have ensured CONFIG_LENOVO_WMI_CAPDATA=y, CONFIG_ACPI_BATTERY=y, and CONFIG_FW_ATTR_CLASS=y.
Quoted 45 lines
Quoted 45 lines
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260326/[email protected]/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
Quoted 2 lines
All errors (new ones prefixed by >>):
ld: vmlinux.o: in function `lwmi_om_fan_get_set':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:206:(.text+0x1b74542): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_attr_01_is_supported':
drivers/platform/x86/lenovo/wmi-other.c:1267:(.text+0x1b74fdf): undefined reference to `lwmi_attr_id'Quoted 2 lines
Quoted 2 lines
ld: drivers/platform/x86/lenovo/wmi-other.c:1270:(.text+0x1b75013): undefined reference to `lwmi_cd01_get_data'
ld: drivers/platform/x86/lenovo/wmi-other.c:1283:(.text+0x1b7515b): undefined reference to `lwmi_attr_id'ld: drivers/platform/x86/lenovo/wmi-other.c:1299:(.text+0x1b752f4): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd_fan':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:565:(.text+0x1b75ca3): undefined reference to `lwmi_cd_fan_get_data'
ld: vmlinux.o: in function `lwmi_psy_prop_is_writeable':
drivers/platform/x86/lenovo/wmi-other.c:687:(.text+0x1b75e2f): undefined reference to `lwmi_attr_id'Quoted 1 line
Quoted 1 line
ld: drivers/platform/x86/lenovo/wmi-other.c:690:(.text+0x1b75e5a): undefined reference to `lwmi_cd00_get_data'
ld: vmlinux.o: in function `lwmi_psy_ext_set_prop':
drivers/platform/x86/lenovo/wmi-other.c:649:(.text+0x1b75f9b): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_psy_ext_get_prop':
drivers/platform/x86/lenovo/wmi-other.c:603:(.text+0x1b761aa): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_other_probe':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1612:(.text+0x1b764eb): undefined reference to `lwmi_cd_match_add_all'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd00':
drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b7680f): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b76838): undefined reference to `lwmi_cd00_get_data' ld: vmlinux.o: in function `lwmi_om_ps_ext_init':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:806:(.text+0x1b76a57): undefined reference to `devm_battery_hook_register'
ld: vmlinux.o: in function `lwmi_om_fw_attr_add':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1474:(.text+0x1b76afa): undefined reference to `firmware_attributes_class'
ld: vmlinux.o: in function `attr_current_value_show':
drivers/platform/x86/lenovo/wmi-other.c:1225:(.text+0x1b77015): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_current_value_store': drivers/platform/x86/lenovo/wmi-other.c:1165:(.text+0x1b776e2): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1168:(.text+0x1b7771c): undefined reference to `lwmi_cd01_get_data' ld: drivers/platform/x86/lenovo/wmi-other.c:1179:(.text+0x1b7781e): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_capdata01_show': drivers/platform/x86/lenovo/wmi-other.c:1099:(.text+0x1b77e38): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1102:(.text+0x1b77e67): undefined reference to `lwmi_cd01_get_data'
Quoted 2 lines
Quoted 2 lines
Kconfigwarnings: (for reference only)
WARNING: unmet direct dependencies detected forLENOVO_WMI_TUNING
When randconfig selects symbols, some are selected by the randomizer, while some are selected by Kconfig select SYMBOL'. In this lkp test, CONFIG_LENOVO_WMI_GAMEZONE=y was selected by the randomizer, while CONFIG_LENOVO_WMI_TUNING=y was selected by select LENOVO_WMI_TUNING' in `config LENOVO_WMI_GAMEZONE'.
Documentation/kbuild/kconfig-language.rst says "select will force a symbol to a value without visiting the dependencies", resulting in unmet dependencies in this test and
https://lore.kernel.org/r/[email protected]
Quoted 49 lines
Quoted 49 lines
Depends on [m]:
X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] &&ACPI_BATTERY[=m] Selected by [y]:
-LENOVO_WMI_GAMEZONE[=y] &&X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] && DMI [=y]vim +206
drivers/platform/x86/lenovo/wmi-other.c51ed34282f63fa Rong Zhang 2026-01-21 186 51ed34282f63fa Rong Zhang 2026-01-21 187 /** 51ed34282f63fa Rong Zhang 2026-01-21 188 * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan 51ed34282f63fa Rong Zhang 2026-01-21 189 * @priv: Driver private data structure 51ed34282f63fa Rong Zhang 2026-01-21 190 * @channel: Fan channel index (0-based) 51ed34282f63fa Rong Zhang 2026-01-21 191 * @val: Pointer to value (input for set, output for get) 51ed34282f63fa Rong Zhang 2026-01-21 192 * @set: True to set value, false to get value 51ed34282f63fa Rong Zhang 2026-01-21 193 * 51ed34282f63fa Rong Zhang 2026-01-21 194 * Communicates with WMI interface to either retrieve current fan RPM 51ed34282f63fa Rong Zhang 2026-01-21 195 * or set target fan RPM. 51ed34282f63fa Rong Zhang 2026-01-21 196 * 51ed34282f63fa Rong Zhang 2026-01-21 197 * Return: 0 on success, or an error code. 51ed34282f63fa Rong Zhang 2026-01-21 198 */ 51ed34282f63fa Rong Zhang 2026-01-21 199 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set) 51ed34282f63fa Rong Zhang 2026-01-21 200 { 51ed34282f63fa Rong Zhang 2026-01-21 201 struct wmi_method_args_32 args; 51ed34282f63fa Rong Zhang 2026-01-21 202 u32 method_id, retval; 51ed34282f63fa Rong Zhang 2026-01-21 203 int err; 51ed34282f63fa Rong Zhang 2026-01-21 204 51ed34282f63fa Rong Zhang 2026-01-21 205 method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET; 51ed34282f63fa Rong Zhang 2026-01-21 @206 args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel); 51ed34282f63fa Rong Zhang 2026-01-21 207 args.arg1 = set ? *val : 0; 51ed34282f63fa Rong Zhang 2026-01-21 208 51ed34282f63fa Rong Zhang 2026-01-21 209 err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id, 51ed34282f63fa Rong Zhang 2026-01-21 210 (unsigned char *)&args, sizeof(args), &retval); 51ed34282f63fa Rong Zhang 2026-01-21 211 if (err) 51ed34282f63fa Rong Zhang 2026-01-21 212 return err; 51ed34282f63fa Rong Zhang 2026-01-21 213 51ed34282f63fa Rong Zhang 2026-01-21 214 if (!set) { 51ed34282f63fa Rong Zhang 2026-01-21 215 *val = retval; 51ed34282f63fa Rong Zhang 2026-01-21 216 return 0; 51ed34282f63fa Rong Zhang 2026-01-21 217 } 51ed34282f63fa Rong Zhang 2026-01-21 218 51ed34282f63fa Rong Zhang 2026-01-21 219 /* 51ed34282f63fa Rong Zhang 2026-01-21 220 * It seems that 0 means "no error" and 1 means "done". Apparently 51ed34282f63fa Rong Zhang 2026-01-21 221 * different firmware teams have different thoughts on indicating 51ed34282f63fa Rong Zhang 2026-01-21 222 * success, so we accepts both. 51ed34282f63fa Rong Zhang 2026-01-21 223 */ 51ed34282f63fa Rong Zhang 2026-01-21 224 return (retval == 0 || retval == 1) ? 0 : -EIO; 51ed34282f63fa Rong Zhang 2026-01-21 225 } 51ed34282f63fa Rong Zhang 2026-01-21 226
Quoted 7 lines
Quoted 3 lines
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wikiCan someone explain to me why this is happening? I cannot reproduce these locally with W=1 and/or C=1. I'd prefer to resolve this before submitting a v6.
The issue exists since commit 6e38b9fcbfa3 ('platform/x86: lenovo:
gamezone needs "other mode"'). It might be a coincidence that lkp didn't running into a similar issue before. IMO `select LENOVO_WMI_TUNING' shouldn't be used in the first place since LENOVO_WMI_TUNING has numerous dependencies.
To fix this, we need to decouple lenovo-wmi-gamezone and lenovo-wmi- other by moving the notifier chain into lenovo-wmi-helpers. I will reply with a patch soon. Fell free to integrate it into your series.
Note that I couldn't completely test my patch since the lack of gamezone support on my device.
BTW, the fix patch has conflicts with my debugfs series since both touch lenovo-wmi-helpers. If you decide to integrate the fix patch into your series, could you integrate the debugfs series into yours too? The conflicts are trivial and contextual. You can resolve them yourself if you don't mind it ;-)
Thanks,
Rong
Quoted 3 lines
Thanks,
Derek
PATCH 1/1 platform/x86: lenovo: Decouple lenovo-wmi-gamezone and lenovo-wmi-other
Currently, lenovo-wmi-gamezone depends on lenovo-wmi-other as the former imports symbols from the latter. The imported symbols are just used to register a notifier block. However, there is no runtime dependency between both drivers, and either of them can run without the other, which is the major purpose of using the notifier framework.
Such a link-time dependency is non-optimal. A previous attempt to "fix" it made LENOVO_WMI_GAMEZONE select LENOVO_WMI_TUNING, which was fundamentally broken and resulted in undefined Kconfig behavior, as `select' cannot be used on a symbol with potentially unmet dependencies.
Decouple both drivers by moving the thermal mode notifier chain to lenovo-wmi-helpers. Methods for notifier block (un)registration are exported for lenovo-wmi-gamezone, while a method for querying the current thermal mode are exported for lenovo-wmi-other.
This turns the dependency graph from
+------------ lenovo-wmi-gamezone
| |
v |
lenovo-wmi-helpers |
^ |
| V
+------------ lenovo-wmi-otherinto
+------------ lenovo-wmi-gamezone
|
v
lenovo-wmi-helpers
^
|
+------------ lenovo-wmi-otherTo make it clear, the name of the notifier chain is also renamed from om_chain_head' to tm_chain_head', indicating that it's used to query the current thermal mode.
No functional change intended.
--- drivers/platform/x86/lenovo/Kconfig | 1 - drivers/platform/x86/lenovo/wmi-gamezone.c | 4 +- drivers/platform/x86/lenovo/wmi-helpers.c | 102 ++++++++++++++++++++ drivers/platform/x86/lenovo/wmi-helpers.h | 8 ++ drivers/platform/x86/lenovo/wmi-other.c | 104 +-------------------- drivers/platform/x86/lenovo/wmi-other.h | 16 ---- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-other.h
drivers/platform/x86/lenovo/Kconfig +0 -1
@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE select ACPI_PLATFORM_PROFILE select LENOVO_WMI_EVENTS select LENOVO_WMI_HELPERS - select LENOVO_WMI_TUNING help Say Y here if you have a WMI aware Lenovo Legion device and would like to use the platform-profile firmware interface to manage power usage.
drivers/platform/x86/lenovo/wmi-gamezone.c +1 -3
@@ -23,7 +23,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"
@@ -383,7 +382,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)return ret; priv->mode_nb.notifier_call = lwmi_gz_mode_call; -return devm_lwmi_om_register_notifier (&wdev->dev, &priv->mode_nb); +return devm_lwmi_tm_register_notifier (&wdev->dev, &priv->mode_nb); }static const struct wmi_device_id lwmi_gz_id_table[] = {
@@ -405,7 +404,6 @@ module_wmi_driver(lwmi_gz_driver);MODULE_IMPORT_NS ("LENOVO_WMI_EVENTS" );MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" ); -MODULE_IMPORT_NS ("LENOVO_WMI_OTHER" );MODULE_DEVICE_TABLE (wmi, lwmi_gz_id_table);MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo GameZone WMI Driver" );
drivers/platform/x86/lenovo/wmi-helpers.c +102 -0
119 lines not on this page · raw message
drivers/platform/x86/lenovo/wmi-helpers.h +8 -0
@@ -7,6 +7,8 @@#include <linux/types.h> +struct device ; +struct notifier_block ;struct wmi_device ;struct wmi_method_args_32 {
@@ -17,4 +19,10 @@ struct wmi_method_args_32 {int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval); +int lwmi_tm_register_notifier (struct notifier_block *nb); +int lwmi_tm_unregister_notifier (struct notifier_block *nb); +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb); +int lwmi_tm_notifier_call (enum thermal_mode *mode); +#endif /* !_LENOVO_WMI_HELPERS_H_ */
drivers/platform/x86/lenovo/wmi-other.c +2 -102
146 lines not on this page · raw message
drivers/platform/x86/lenovo/wmi-other.h deleted +0 -16
@@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* Copyright (C) 2025 Derek J. Clark <[email protected]> */ - -#ifndef _LENOVO_WMI_OTHER_H_ -#define _LENOVO_WMI_OTHER_H_ - -struct device ; -struct notifier_block ; - -int lwmi_om_register_notifier (struct notifier_block *nb); -int lwmi_om_unregister_notifier (struct notifier_block *nb); -int devm_lwmi_om_register_notifier (struct device *dev, -struct notifier_block *nb); - -#endif /* !_LENOVO_WMI_OTHER_H_ */
base-commit: 0138af2472dfdef0d56fc4697416eaa0ff2589bd
Signature · 1 line
2.53.0
Ilpo Järvinen
maintainerRe: [PATCH] platform/x86: lenovo: Decouple lenovo-wmi-gamezone and lenovo-wmi-other
Quoted 238 lines · Rong Zhang
Currently, lenovo-wmi-gamezone depends on lenovo-wmi-other as the former imports symbols from the latter. The imported symbols are just used to register a notifier block. However, there is no runtime dependency between both drivers, and either of them can run without the other, which is the major purpose of using the notifier framework.
Such a link-time dependency is non-optimal. A previous attempt to "fix" it made
LENOVO_WMI_GAMEZONEselectLENOVO_WMI_TUNING, which was fundamentally broken and resulted in undefinedKconfigbehavior, as `select' cannot be used on a symbol with potentially unmet dependencies.Decouple both drivers by moving the thermal mode notifier chain to lenovo-wmi-helpers. Methods for notifier block (un)registration are exported for lenovo-wmi-gamezone, while a method for querying the current thermal mode are exported for lenovo-wmi-other.
This turns the dependency graph from
+------------ lenovo-wmi-gamezone | | v | lenovo-wmi-helpers | ^ | | V +------------ lenovo-wmi-otherinto
+------------ lenovo-wmi-gamezone | v lenovo-wmi-helpers ^ | +------------ lenovo-wmi-otherTo make it clear, the name of the notifier chain is also renamed from
om_chain_head' totm_chain_head', indicating that it's used to query the current thermal mode.No functional change intended.
Fixes 6e38b9fcbfa3 ("platform/x86: lenovo: gamezone needs "other mode"")Reported-by kernel test robot <[email protected]>Signed-off-by Rong Zhang <[email protected]>--- drivers/platform/x86/lenovo/Kconfig | 1 - drivers/platform/x86/lenovo/wmi-gamezone.c | 4 +- drivers/platform/x86/lenovo/wmi-helpers.c | 102 ++++++++++++++++++++ drivers/platform/x86/lenovo/wmi-helpers.h | 8 ++ drivers/platform/x86/lenovo/wmi-other.c | 104 +-------------------- drivers/platform/x86/lenovo/wmi-other.h | 16 ---- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-other.hdrivers/platform/x86/lenovo/Kconfig +0
-1@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE select ACPI_PLATFORM_PROFILE select LENOVO_WMI_EVENTS select LENOVO_WMI_HELPERS - select LENOVO_WMI_TUNING help Say Y here if you have a WMI aware Lenovo Legion device and would like to use the platform-profile firmware interface to manage power usage.drivers/platform/x86/lenovo/wmi-gamezone.c +1
-3@@ -23,7 +23,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"@@ -383,7 +382,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)return ret; priv->mode_nb.notifier_call = lwmi_gz_mode_call; -return devm_lwmi_om_register_notifier (&wdev->dev, &priv->mode_nb); +return devm_lwmi_tm_register_notifier (&wdev->dev, &priv->mode_nb); }static const struct wmi_device_id lwmi_gz_id_table[] = {@@ -405,7 +404,6 @@ module_wmi_driver(lwmi_gz_driver);MODULE_IMPORT_NS ("LENOVO_WMI_EVENTS" );MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" ); -MODULE_IMPORT_NS ("LENOVO_WMI_OTHER" );MODULE_DEVICE_TABLE (wmi, lwmi_gz_id_table);MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo GameZone WMI Driver" );drivers/platform/x86/lenovo/wmi-helpers.c +102
-0@@ -21,11 +21,16 @@#include <linux/errno.h> #include <linux/export.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/unaligned.h> #include <linux/wmi.h> +#include "wmi-gamezone.h" #include "wmi-helpers.h" +/* Thermal mode notifier chain. */ +static BLOCKING_NOTIFIER_HEAD (tm_chain_head); +/** * lwmi_dev_evaluate_int() - Helper function for calling WMI methods that * return an integer. @@ -84,6 +89,103 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id, };EXPORT_SYMBOL_NS_GPL (lwmi_dev_evaluate_int,"LENOVO_WMI_HELPERS" ); +/** +* lwmi_tm_register_notifier() - Add a notifier to the blocking notifier chain +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_register to register the notifier block to the +* thermal mode notifier chain. +* +* Return: 0 on success, %-EEXIST on error. +*/ +int lwmi_tm_register_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_unregister_notifier() - Remove a notifier from the blocking notifier +* chain. +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_unregister to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +int lwmi_tm_unregister_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_unregister_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* devm_lwmi_tm_unregister_notifier() - Remove a notifier from the blocking +* notifier chain. +* @data: Void pointer to the notifier_block struct to register. +* +* Call lwmi_tm_unregister_notifier to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +static void devm_lwmi_tm_unregister_notifier (void *data) +{ +struct notifier_block *nb = data; + +lwmi_tm_unregister_notifier (nb); +} + +/** +* devm_lwmi_tm_register_notifier() - Add a notifier to the blocking notifier +* chain. +* @dev: The parent device of the notifier_block struct. +* @nb: The notifier_block struct to register +* +* Call lwmi_tm_register_notifier to register the notifier block to the +* thermal mode notifier chain. Then add devm_lwmi_tm_unregister_notifier +* as a device managed action to automatically unregister the notifier block +* upon parent device removal. +* +* Return: 0 on success, or an error code. +*/ +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb) +{ +int ret; + + ret =lwmi_tm_register_notifier (nb); +if (ret <0 ) +return ret; + +return devm_add_action_or_reset (dev, devm_lwmi_tm_unregister_notifier, + nb); +} +EXPORT_SYMBOL_NS_GPL (devm_lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_notifier_call() - Call functions for the notifier call chain. +* @mode: Pointer to a thermal mode enum to retrieve the data from. +* +* Call blocking_notifier_call_chain to retrieve the thermal mode from the +* lenovo-wmi-gamezone driver. +* +* Return: 0 on success, or an error code. +*/ +int lwmi_tm_notifier_call (enum thermal_mode *mode) +{ +int ret; + + ret =blocking_notifier_call_chain (&tm_chain_head, +LWMI_GZ_GET_THERMAL_MODE , &mode); +if ((ret & ~NOTIFY_STOP_MASK ) !=NOTIFY_OK ) +return -EINVAL ; + +return 0 ; +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_notifier_call,"LENOVO_WMI_HELPERS" ); +MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo WMI Helpers Driver" );MODULE_LICENSE ("GPL" );drivers/platform/x86/lenovo/wmi-helpers.h +2
-0@@ -7,6 +7,8 @@#include <linux/types.h> +struct device ; +struct notifier_block ;struct wmi_device ;struct wmi_method_args_32 {
drivers/platform/x86/lenovo/wmi-helpers.h struct wmi_method_args_32 { · line 26
Quoted 8 lines
drivers/platform/x86/lenovo/wmi-helpers.h +5
-0@@ -17,4 +19,10 @@ struct wmi_method_args_32 {int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval); +int lwmi_tm_register_notifier (struct notifier_block *nb); +int lwmi_tm_unregister_notifier (struct notifier_block *nb); +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb); +int lwmi_tm_notifier_call (enum thermal_mode *mode);
This enum is not introduced earlier within this header?
Signature · 1 line
i.
Quoted 184 lines
drivers/platform/x86/lenovo/wmi-helpers.h +1
-0+#endif /* !_LENOVO_WMI_HELPERS_H_ */ drivers/platform/x86/lenovo/wmi-other.c +2
-102@@ -40,7 +40,6 @@#include <linux/kobject.h> #include <linux/limits.h> #include <linux/module.h> -#include <linux/notifier.h> #include <linux/platform_profile.h> #include <linux/types.h> #include <linux/wmi.h> @@ -49,7 +48,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #include "../firmware_attributes_class.h" #define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"@@ -81,7 +79,6 @@#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"#define LWMI_OM_HWMON_NAME "lenovo_wmi_other" -static BLOCKING_NOTIFIER_HEAD (om_chain_head);static DEFINE_IDA (lwmi_om_ida);enum attribute_property {@@ -109,7 +106,6 @@ struct lwmi_om_priv {struct device *hwmon_dev;struct device *fw_attr_dev;struct kset *fw_attr_kset; -struct notifier_block nb;struct wmi_device *wdev;int ida_id;@@ -576,102 +572,6 @@ struct capdata01_attr_group {struct tunable_attr_01 *tunable_attr; }; -/** -* lwmi_om_register_notifier() - Add a notifier to the blocking notifier chain -* @nb: The notifier_block struct to register -* -* Call blocking_notifier_chain_register to register the notifier block to the -* lenovo-wmi-other driver notifier chain. -* -* Return: 0 on success, %-EEXIST on error. -*/ -int lwmi_om_register_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_register (&om_chain_head, nb); -} -EXPORT_SYMBOL_NS_GPL (lwmi_om_register_notifier,"LENOVO_WMI_OTHER" ); - -/** -* lwmi_om_unregister_notifier() - Remove a notifier from the blocking notifier -* chain. -* @nb: The notifier_block struct to register -* -* Call blocking_notifier_chain_unregister to unregister the notifier block from the -* lenovo-wmi-other driver notifier chain. -* -* Return: 0 on success, %-ENOENT on error. -*/ -int lwmi_om_unregister_notifier (struct notifier_block *nb) -{ -return blocking_notifier_chain_unregister (&om_chain_head, nb); -} -EXPORT_SYMBOL_NS_GPL (lwmi_om_unregister_notifier,"LENOVO_WMI_OTHER" ); - -/** -* devm_lwmi_om_unregister_notifier() - Remove a notifier from the blocking -* notifier chain. -* @data: Void pointer to the notifier_block struct to register. -* -* Call lwmi_om_unregister_notifier to unregister the notifier block from the -* lenovo-wmi-other driver notifier chain. -* -* Return: 0 on success, %-ENOENT on error. -*/ -static void devm_lwmi_om_unregister_notifier (void *data) -{ -struct notifier_block *nb = data; - -lwmi_om_unregister_notifier (nb); -} - -/** -* devm_lwmi_om_register_notifier() - Add a notifier to the blocking notifier -* chain. -* @dev: The parent device of the notifier_block struct. -* @nb: The notifier_block struct to register -* -* Call lwmi_om_register_notifier to register the notifier block to the -* lenovo-wmi-other driver notifier chain. Then add devm_lwmi_om_unregister_notifier -* as a device managed action to automatically unregister the notifier block -* upon parent device removal. -* -* Return: 0 on success, or an error code. -*/ -int devm_lwmi_om_register_notifier (struct device *dev, -struct notifier_block *nb) -{ -int ret; - - ret =lwmi_om_register_notifier (nb); -if (ret <0 ) -return ret; - -return devm_add_action_or_reset (dev, devm_lwmi_om_unregister_notifier, - nb); -} -EXPORT_SYMBOL_NS_GPL (devm_lwmi_om_register_notifier,"LENOVO_WMI_OTHER" ); - -/** -* lwmi_om_notifier_call() - Call functions for the notifier call chain. -* @mode: Pointer to a thermal mode enum to retrieve the data from. -* -* Call blocking_notifier_call_chain to retrieve the thermal mode from the -* lenovo-wmi-gamezone driver. -* -* Return: 0 on success, or an error code. -*/ -static int lwmi_om_notifier_call (enum thermal_mode *mode) -{ -int ret; - - ret =blocking_notifier_call_chain (&om_chain_head, -LWMI_GZ_GET_THERMAL_MODE , &mode); -if ((ret & ~NOTIFY_STOP_MASK ) !=NOTIFY_OK ) -return -EINVAL ; - -return 0 ; -} -/* Attribute Methods */ /** @@ -780,7 +680,7 @@ static ssize_t attr_current_value_store(struct kobject *kobj,u32 value;int ret; - ret =lwmi_om_notifier_call (&mode); + ret =lwmi_tm_notifier_call (&mode);if (ret)return ret;@@ -842,7 +742,7 @@ static ssize_t attr_current_value_show(struct kobject *kobj,int retval;int ret; - ret =lwmi_om_notifier_call (&mode); + ret =lwmi_tm_notifier_call (&mode);if (ret)return ret;drivers/platform/x86/lenovo/wmi-other.h deleted +0
-16@@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/* Copyright (C) 2025 Derek J. Clark <[email protected]> */ - -#ifndef _LENOVO_WMI_OTHER_H_ -#define _LENOVO_WMI_OTHER_H_ - -struct device ; -struct notifier_block ; - -int lwmi_om_register_notifier (struct notifier_block *nb); -int lwmi_om_unregister_notifier (struct notifier_block *nb); -int devm_lwmi_om_register_notifier (struct device *dev, -struct notifier_block *nb); - -#endif /* !_LENOVO_WMI_OTHER_H_ */ base-commit:
0138af2472dfdef0d56fc4697416eaa0ff2589bd
Re: [PATCH] platform/x86: lenovo: Decouple lenovo-wmi-gamezone and lenovo-wmi-other
Hi Ilpo,
Quoted 243 lines · Ilpo Järvinen
Quoted 241 lines · Rong Zhang
Currently, lenovo-wmi-gamezone depends on lenovo-wmi-other as the former imports symbols from the latter. The imported symbols are just used to register a notifier block. However, there is no runtime dependency between both drivers, and either of them can run without the other, which is the major purpose of using the notifier framework.
Such a link-time dependency is non-optimal. A previous attempt to "fix" it made
LENOVO_WMI_GAMEZONEselectLENOVO_WMI_TUNING, which was fundamentally broken and resulted in undefinedKconfigbehavior, as `select' cannot be used on a symbol with potentially unmet dependencies.Decouple both drivers by moving the thermal mode notifier chain to lenovo-wmi-helpers. Methods for notifier block (un)registration are exported for lenovo-wmi-gamezone, while a method for querying the current thermal mode are exported for lenovo-wmi-other.
This turns the dependency graph from
+------------ lenovo-wmi-gamezone | | v | lenovo-wmi-helpers | ^ | | V +------------ lenovo-wmi-otherinto
+------------ lenovo-wmi-gamezone | v lenovo-wmi-helpers ^ | +------------ lenovo-wmi-otherTo make it clear, the name of the notifier chain is also renamed from
om_chain_head' totm_chain_head', indicating that it's used to query the current thermal mode.No functional change intended.
Fixes 6e38b9fcbfa3 ("platform/x86: lenovo: gamezone needs "other mode"")Reported-by kernel test robot <[email protected]>Signed-off-by Rong Zhang <[email protected]>--- drivers/platform/x86/lenovo/Kconfig | 1 - drivers/platform/x86/lenovo/wmi-gamezone.c | 4 +- drivers/platform/x86/lenovo/wmi-helpers.c | 102 ++++++++++++++++++++ drivers/platform/x86/lenovo/wmi-helpers.h | 8 ++ drivers/platform/x86/lenovo/wmi-other.c | 104 +-------------------- drivers/platform/x86/lenovo/wmi-other.h | 16 ---- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-other.hdrivers/platform/x86/lenovo/Kconfig +0
-1@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE select ACPI_PLATFORM_PROFILE select LENOVO_WMI_EVENTS select LENOVO_WMI_HELPERS - select LENOVO_WMI_TUNING help Say Y here if you have a WMI aware Lenovo Legion device and would like to use the platform-profile firmware interface to manage power usage.drivers/platform/x86/lenovo/wmi-gamezone.c +1
-3@@ -23,7 +23,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"@@ -383,7 +382,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)return ret; priv->mode_nb.notifier_call = lwmi_gz_mode_call; -return devm_lwmi_om_register_notifier (&wdev->dev, &priv->mode_nb); +return devm_lwmi_tm_register_notifier (&wdev->dev, &priv->mode_nb); }static const struct wmi_device_id lwmi_gz_id_table[] = {@@ -405,7 +404,6 @@ module_wmi_driver(lwmi_gz_driver);MODULE_IMPORT_NS ("LENOVO_WMI_EVENTS" );MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" ); -MODULE_IMPORT_NS ("LENOVO_WMI_OTHER" );MODULE_DEVICE_TABLE (wmi, lwmi_gz_id_table);MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo GameZone WMI Driver" );drivers/platform/x86/lenovo/wmi-helpers.c +102
-0@@ -21,11 +21,16 @@#include <linux/errno.h> #include <linux/export.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/unaligned.h> #include <linux/wmi.h> +#include "wmi-gamezone.h" #include "wmi-helpers.h" +/* Thermal mode notifier chain. */ +static BLOCKING_NOTIFIER_HEAD (tm_chain_head); +/** * lwmi_dev_evaluate_int() - Helper function for calling WMI methods that * return an integer. @@ -84,6 +89,103 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id, };EXPORT_SYMBOL_NS_GPL (lwmi_dev_evaluate_int,"LENOVO_WMI_HELPERS" ); +/** +* lwmi_tm_register_notifier() - Add a notifier to the blocking notifier chain +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_register to register the notifier block to the +* thermal mode notifier chain. +* +* Return: 0 on success, %-EEXIST on error. +*/ +int lwmi_tm_register_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_unregister_notifier() - Remove a notifier from the blocking notifier +* chain. +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_unregister to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +int lwmi_tm_unregister_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_unregister_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* devm_lwmi_tm_unregister_notifier() - Remove a notifier from the blocking +* notifier chain. +* @data: Void pointer to the notifier_block struct to register. +* +* Call lwmi_tm_unregister_notifier to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +static void devm_lwmi_tm_unregister_notifier (void *data) +{ +struct notifier_block *nb = data; + +lwmi_tm_unregister_notifier (nb); +} + +/** +* devm_lwmi_tm_register_notifier() - Add a notifier to the blocking notifier +* chain. +* @dev: The parent device of the notifier_block struct. +* @nb: The notifier_block struct to register +* +* Call lwmi_tm_register_notifier to register the notifier block to the +* thermal mode notifier chain. Then add devm_lwmi_tm_unregister_notifier +* as a device managed action to automatically unregister the notifier block +* upon parent device removal. +* +* Return: 0 on success, or an error code. +*/ +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb) +{ +int ret; + + ret =lwmi_tm_register_notifier (nb); +if (ret <0 ) +return ret; + +return devm_add_action_or_reset (dev, devm_lwmi_tm_unregister_notifier, + nb); +} +EXPORT_SYMBOL_NS_GPL (devm_lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_notifier_call() - Call functions for the notifier call chain. +* @mode: Pointer to a thermal mode enum to retrieve the data from. +* +* Call blocking_notifier_call_chain to retrieve the thermal mode from the +* lenovo-wmi-gamezone driver. +* +* Return: 0 on success, or an error code. +*/ +int lwmi_tm_notifier_call (enum thermal_mode *mode) +{ +int ret; + + ret =blocking_notifier_call_chain (&tm_chain_head, +LWMI_GZ_GET_THERMAL_MODE , &mode); +if ((ret & ~NOTIFY_STOP_MASK ) !=NOTIFY_OK ) +return -EINVAL ; + +return 0 ; +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_notifier_call,"LENOVO_WMI_HELPERS" ); +MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo WMI Helpers Driver" );MODULE_LICENSE ("GPL" );drivers/platform/x86/lenovo/wmi-helpers.h +2
-0@@ -7,6 +7,8 @@#include <linux/types.h> +struct device ; +struct notifier_block ;struct wmi_device ;struct wmi_method_args_32 {@@ -17,4 +19,10 @@ struct wmi_method_args_32 {int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval);
Quoted 7 lines
drivers/platform/x86/lenovo/wmi-helpers.h struct wmi_method_args_32 { · line 26
Quoted 5 lines
drivers/platform/x86/lenovo/wmi-helpers.h +5
-0+int lwmi_tm_register_notifier (struct notifier_block *nb); +int lwmi_tm_unregister_notifier (struct notifier_block *nb); +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb); +int lwmi_tm_notifier_call (enum thermal_mode *mode);This enum is not introduced earlier within this header?
Hmm, no. Declaring a opaque enum earlier should be enough to fix it, as wmi-gamezone.h shouldn't be included here. Derek, what do you think?
Thanks,
Rong
Derek John Clark
maintainerRe: [PATCH] platform/x86: lenovo: Decouple lenovo-wmi-gamezone and lenovo-wmi-other
Quoted 255 lines · Rong Zhang
Hi Ilpo,
Quoted 243 lines · Ilpo Järvinen
Quoted 241 lines · Rong Zhang
Currently, lenovo-wmi-gamezone depends on lenovo-wmi-other as the former imports symbols from the latter. The imported symbols are just used to register a notifier block. However, there is no runtime dependency between both drivers, and either of them can run without the other, which is the major purpose of using the notifier framework.
Such a link-time dependency is non-optimal. A previous attempt to "fix" it made
LENOVO_WMI_GAMEZONEselectLENOVO_WMI_TUNING, which was fundamentally broken and resulted in undefinedKconfigbehavior, as `select' cannot be used on a symbol with potentially unmet dependencies.Decouple both drivers by moving the thermal mode notifier chain to lenovo-wmi-helpers. Methods for notifier block (un)registration are exported for lenovo-wmi-gamezone, while a method for querying the current thermal mode are exported for lenovo-wmi-other.
This turns the dependency graph from
+------------ lenovo-wmi-gamezone | | v | lenovo-wmi-helpers | ^ | | V +------------ lenovo-wmi-otherinto
+------------ lenovo-wmi-gamezone | v lenovo-wmi-helpers ^ | +------------ lenovo-wmi-otherTo make it clear, the name of the notifier chain is also renamed from
om_chain_head' totm_chain_head', indicating that it's used to query the current thermal mode.No functional change intended.
Fixes 6e38b9fcbfa3 ("platform/x86: lenovo: gamezone needs "other mode"")Reported-by kernel test robot <[email protected]>Signed-off-by Rong Zhang <[email protected]>--- drivers/platform/x86/lenovo/Kconfig | 1 - drivers/platform/x86/lenovo/wmi-gamezone.c | 4 +- drivers/platform/x86/lenovo/wmi-helpers.c | 102 ++++++++++++++++++++ drivers/platform/x86/lenovo/wmi-helpers.h | 8 ++ drivers/platform/x86/lenovo/wmi-other.c | 104 +-------------------- drivers/platform/x86/lenovo/wmi-other.h | 16 ---- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-other.hdrivers/platform/x86/lenovo/Kconfig +0
-1@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE select ACPI_PLATFORM_PROFILE select LENOVO_WMI_EVENTS select LENOVO_WMI_HELPERS - select LENOVO_WMI_TUNING help Say Y here if you have a WMI aware Lenovo Legion device and would like to use the platform-profile firmware interface to manage power usage.drivers/platform/x86/lenovo/wmi-gamezone.c +1
-3@@ -23,7 +23,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"@@ -383,7 +382,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)return ret; priv->mode_nb.notifier_call = lwmi_gz_mode_call; -return devm_lwmi_om_register_notifier (&wdev->dev, &priv->mode_nb); +return devm_lwmi_tm_register_notifier (&wdev->dev, &priv->mode_nb); }static const struct wmi_device_id lwmi_gz_id_table[] = {@@ -405,7 +404,6 @@ module_wmi_driver(lwmi_gz_driver);MODULE_IMPORT_NS ("LENOVO_WMI_EVENTS" );MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" ); -MODULE_IMPORT_NS ("LENOVO_WMI_OTHER" );MODULE_DEVICE_TABLE (wmi, lwmi_gz_id_table);MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo GameZone WMI Driver" );drivers/platform/x86/lenovo/wmi-helpers.c +102
-0@@ -21,11 +21,16 @@#include <linux/errno.h> #include <linux/export.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/unaligned.h> #include <linux/wmi.h> +#include "wmi-gamezone.h" #include "wmi-helpers.h" +/* Thermal mode notifier chain. */ +static BLOCKING_NOTIFIER_HEAD (tm_chain_head); +/** * lwmi_dev_evaluate_int() - Helper function for calling WMI methods that * return an integer. @@ -84,6 +89,103 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id, };EXPORT_SYMBOL_NS_GPL (lwmi_dev_evaluate_int,"LENOVO_WMI_HELPERS" ); +/** +* lwmi_tm_register_notifier() - Add a notifier to the blocking notifier chain +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_register to register the notifier block to the +* thermal mode notifier chain. +* +* Return: 0 on success, %-EEXIST on error. +*/ +int lwmi_tm_register_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_unregister_notifier() - Remove a notifier from the blocking notifier +* chain. +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_unregister to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +int lwmi_tm_unregister_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_unregister_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* devm_lwmi_tm_unregister_notifier() - Remove a notifier from the blocking +* notifier chain. +* @data: Void pointer to the notifier_block struct to register. +* +* Call lwmi_tm_unregister_notifier to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +static void devm_lwmi_tm_unregister_notifier (void *data) +{ +struct notifier_block *nb = data; + +lwmi_tm_unregister_notifier (nb); +} + +/** +* devm_lwmi_tm_register_notifier() - Add a notifier to the blocking notifier +* chain. +* @dev: The parent device of the notifier_block struct. +* @nb: The notifier_block struct to register +* +* Call lwmi_tm_register_notifier to register the notifier block to the +* thermal mode notifier chain. Then add devm_lwmi_tm_unregister_notifier +* as a device managed action to automatically unregister the notifier block +* upon parent device removal. +* +* Return: 0 on success, or an error code. +*/ +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb) +{ +int ret; + + ret =lwmi_tm_register_notifier (nb); +if (ret <0 ) +return ret; + +return devm_add_action_or_reset (dev, devm_lwmi_tm_unregister_notifier, + nb); +} +EXPORT_SYMBOL_NS_GPL (devm_lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_notifier_call() - Call functions for the notifier call chain. +* @mode: Pointer to a thermal mode enum to retrieve the data from. +* +* Call blocking_notifier_call_chain to retrieve the thermal mode from the +* lenovo-wmi-gamezone driver. +* +* Return: 0 on success, or an error code. +*/ +int lwmi_tm_notifier_call (enum thermal_mode *mode) +{ +int ret; + + ret =blocking_notifier_call_chain (&tm_chain_head, +LWMI_GZ_GET_THERMAL_MODE , &mode); +if ((ret & ~NOTIFY_STOP_MASK ) !=NOTIFY_OK ) +return -EINVAL ; + +return 0 ; +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_notifier_call,"LENOVO_WMI_HELPERS" ); +MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo WMI Helpers Driver" );MODULE_LICENSE ("GPL" );drivers/platform/x86/lenovo/wmi-helpers.h +2
-0@@ -7,6 +7,8 @@#include <linux/types.h> +struct device ; +struct notifier_block ;struct wmi_device ;struct wmi_method_args_32 {@@ -17,4 +19,10 @@ struct wmi_method_args_32 {int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval);Quoted 7 lines
drivers/platform/x86/lenovo/wmi-helpers.h struct wmi_method_args_32 { · line 26
Quoted 5 lines
drivers/platform/x86/lenovo/wmi-helpers.h +5
-0+int lwmi_tm_register_notifier (struct notifier_block *nb); +int lwmi_tm_unregister_notifier (struct notifier_block *nb); +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb); +int lwmi_tm_notifier_call (enum thermal_mode *mode);This enum is not introduced earlier within this header?
Quoted 2 lines
Hmm, no. Declaring a opaque enum earlier should be enough to fix it, as
wmi-gamezone.hshouldn't be included here. Derek, what do you think?
I think it makes more sense at this point to move everything from wmi_gamezone.h into wmi_helpers.h. This prevents wmi_capdata.c from needing to import wmi_gamezone.h, since the thermal mode enum will be moved (now used by capdata, gamezone, and other). Then the only thing in the gamezone header would be the gamezone_events_type enum, which is only used by gamezone and helpers anyway, so that can safely move and we can delete the entire file. To make that enum name more generic I'll rename it in the move from gamezone_events_type to lwmi_event_type (the enum isn't directly referenced anywhere anyway).
If that works for everyone I'll add one more patch to do the move & cleanup before "platform/x86: lenovo-wmi-other: Add lwmi_attr_id() function" where I'm adding the .._NONE thermal mode. That will keep the purpose of each patch clean and avoid me needing to modify your patches too much.
Thanks,
Derek.
Quoted 2 lines
Thanks,
Rong
Re: [PATCH] platform/x86: lenovo: Decouple lenovo-wmi-gamezone and lenovo-wmi-other
Hi Derek,
Quoted 269 lines · Derek John Clark
Quoted 255 lines · Rong Zhang
Hi Ilpo,
Quoted 243 lines · Ilpo Järvinen
Quoted 241 lines · Rong Zhang
Currently, lenovo-wmi-gamezone depends on lenovo-wmi-other as the former imports symbols from the latter. The imported symbols are just used to register a notifier block. However, there is no runtime dependency between both drivers, and either of them can run without the other, which is the major purpose of using the notifier framework.
Such a link-time dependency is non-optimal. A previous attempt to "fix" it made
LENOVO_WMI_GAMEZONEselectLENOVO_WMI_TUNING, which was fundamentally broken and resulted in undefinedKconfigbehavior, as `select' cannot be used on a symbol with potentially unmet dependencies.Decouple both drivers by moving the thermal mode notifier chain to lenovo-wmi-helpers. Methods for notifier block (un)registration are exported for lenovo-wmi-gamezone, while a method for querying the current thermal mode are exported for lenovo-wmi-other.
This turns the dependency graph from
+------------ lenovo-wmi-gamezone | | v | lenovo-wmi-helpers | ^ | | V +------------ lenovo-wmi-otherinto
+------------ lenovo-wmi-gamezone | v lenovo-wmi-helpers ^ | +------------ lenovo-wmi-otherTo make it clear, the name of the notifier chain is also renamed from
om_chain_head' totm_chain_head', indicating that it's used to query the current thermal mode.No functional change intended.
Fixes 6e38b9fcbfa3 ("platform/x86: lenovo: gamezone needs "other mode"")Reported-by kernel test robot <[email protected]>Signed-off-by Rong Zhang <[email protected]>--- drivers/platform/x86/lenovo/Kconfig | 1 - drivers/platform/x86/lenovo/wmi-gamezone.c | 4 +- drivers/platform/x86/lenovo/wmi-helpers.c | 102 ++++++++++++++++++++ drivers/platform/x86/lenovo/wmi-helpers.h | 8 ++ drivers/platform/x86/lenovo/wmi-other.c | 104 +-------------------- drivers/platform/x86/lenovo/wmi-other.h | 16 ---- 6 files changed, 113 insertions(+), 122 deletions(-) delete mode 100644 drivers/platform/x86/lenovo/wmi-other.hdrivers/platform/x86/lenovo/Kconfig +0
-1@@ -252,7 +252,6 @@ config LENOVO_WMI_GAMEZONE select ACPI_PLATFORM_PROFILE select LENOVO_WMI_EVENTS select LENOVO_WMI_HELPERS - select LENOVO_WMI_TUNING help Say Y here if you have a WMI aware Lenovo Legion device and would like to use the platform-profile firmware interface to manage power usage.drivers/platform/x86/lenovo/wmi-gamezone.c +1
-3@@ -23,7 +23,6 @@#include "wmi-events.h" #include "wmi-gamezone.h" #include "wmi-helpers.h" -#include "wmi-other.h" #define LENOVO_GAMEZONE_GUID "887B54E3-DDDC-4B2C-8B88-68A26A8835D0"@@ -383,7 +382,7 @@ static int lwmi_gz_probe(struct wmi_device *wdev, const void *context)return ret; priv->mode_nb.notifier_call = lwmi_gz_mode_call; -return devm_lwmi_om_register_notifier (&wdev->dev, &priv->mode_nb); +return devm_lwmi_tm_register_notifier (&wdev->dev, &priv->mode_nb); }static const struct wmi_device_id lwmi_gz_id_table[] = {@@ -405,7 +404,6 @@ module_wmi_driver(lwmi_gz_driver);MODULE_IMPORT_NS ("LENOVO_WMI_EVENTS" );MODULE_IMPORT_NS ("LENOVO_WMI_HELPERS" ); -MODULE_IMPORT_NS ("LENOVO_WMI_OTHER" );MODULE_DEVICE_TABLE (wmi, lwmi_gz_id_table);MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo GameZone WMI Driver" );drivers/platform/x86/lenovo/wmi-helpers.c +102
-0@@ -21,11 +21,16 @@#include <linux/errno.h> #include <linux/export.h> #include <linux/module.h> +#include <linux/notifier.h> #include <linux/unaligned.h> #include <linux/wmi.h> +#include "wmi-gamezone.h" #include "wmi-helpers.h" +/* Thermal mode notifier chain. */ +static BLOCKING_NOTIFIER_HEAD (tm_chain_head); +/** * lwmi_dev_evaluate_int() - Helper function for calling WMI methods that * return an integer. @@ -84,6 +89,103 @@ int lwmi_dev_evaluate_int(struct wmi_device *wdev, u8 instance, u32 method_id, };EXPORT_SYMBOL_NS_GPL (lwmi_dev_evaluate_int,"LENOVO_WMI_HELPERS" ); +/** +* lwmi_tm_register_notifier() - Add a notifier to the blocking notifier chain +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_register to register the notifier block to the +* thermal mode notifier chain. +* +* Return: 0 on success, %-EEXIST on error. +*/ +int lwmi_tm_register_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_register (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_unregister_notifier() - Remove a notifier from the blocking notifier +* chain. +* @nb: The notifier_block struct to register +* +* Call blocking_notifier_chain_unregister to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +int lwmi_tm_unregister_notifier (struct notifier_block *nb) +{ +return blocking_notifier_chain_unregister (&tm_chain_head, nb); +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_unregister_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* devm_lwmi_tm_unregister_notifier() - Remove a notifier from the blocking +* notifier chain. +* @data: Void pointer to the notifier_block struct to register. +* +* Call lwmi_tm_unregister_notifier to unregister the notifier block from the +* thermal mode notifier chain. +* +* Return: 0 on success, %-ENOENT on error. +*/ +static void devm_lwmi_tm_unregister_notifier (void *data) +{ +struct notifier_block *nb = data; + +lwmi_tm_unregister_notifier (nb); +} + +/** +* devm_lwmi_tm_register_notifier() - Add a notifier to the blocking notifier +* chain. +* @dev: The parent device of the notifier_block struct. +* @nb: The notifier_block struct to register +* +* Call lwmi_tm_register_notifier to register the notifier block to the +* thermal mode notifier chain. Then add devm_lwmi_tm_unregister_notifier +* as a device managed action to automatically unregister the notifier block +* upon parent device removal. +* +* Return: 0 on success, or an error code. +*/ +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb) +{ +int ret; + + ret =lwmi_tm_register_notifier (nb); +if (ret <0 ) +return ret; + +return devm_add_action_or_reset (dev, devm_lwmi_tm_unregister_notifier, + nb); +} +EXPORT_SYMBOL_NS_GPL (devm_lwmi_tm_register_notifier,"LENOVO_WMI_HELPERS" ); + +/** +* lwmi_tm_notifier_call() - Call functions for the notifier call chain. +* @mode: Pointer to a thermal mode enum to retrieve the data from. +* +* Call blocking_notifier_call_chain to retrieve the thermal mode from the +* lenovo-wmi-gamezone driver. +* +* Return: 0 on success, or an error code. +*/ +int lwmi_tm_notifier_call (enum thermal_mode *mode) +{ +int ret; + + ret =blocking_notifier_call_chain (&tm_chain_head, +LWMI_GZ_GET_THERMAL_MODE , &mode); +if ((ret & ~NOTIFY_STOP_MASK ) !=NOTIFY_OK ) +return -EINVAL ; + +return 0 ; +} +EXPORT_SYMBOL_NS_GPL (lwmi_tm_notifier_call,"LENOVO_WMI_HELPERS" ); +MODULE_AUTHOR ("Derek J. Clark <[email protected]>" );MODULE_DESCRIPTION ("Lenovo WMI Helpers Driver" );MODULE_LICENSE ("GPL" );drivers/platform/x86/lenovo/wmi-helpers.h +2
-0@@ -7,6 +7,8 @@#include <linux/types.h> +struct device ; +struct notifier_block ;struct wmi_device ;struct wmi_method_args_32 {@@ -17,4 +19,10 @@ struct wmi_method_args_32 {int lwmi_dev_evaluate_int (struct wmi_device *wdev,u8 instance,u32 method_id,unsigned char *buf,size_t size,u32 *retval);Quoted 7 lines
drivers/platform/x86/lenovo/wmi-helpers.h struct wmi_method_args_32 { · line 26
Quoted 5 lines
drivers/platform/x86/lenovo/wmi-helpers.h +5
-0+int lwmi_tm_register_notifier (struct notifier_block *nb); +int lwmi_tm_unregister_notifier (struct notifier_block *nb); +int devm_lwmi_tm_register_notifier (struct device *dev, +struct notifier_block *nb); +int lwmi_tm_notifier_call (enum thermal_mode *mode);This enum is not introduced earlier within this header?
Quoted 2 lines
Hmm, no. Declaring a opaque enum earlier should be enough to fix it, as
wmi-gamezone.hshouldn't be included here. Derek, what do you think?I think it makes more sense at this point to move everything from
wmi_gamezone.hintowmi_helpers.h. This preventswmi_capdata.cfrom needing to importwmi_gamezone.h, since the thermal mode enum will be moved (now used by capdata, gamezone, and other). Then the only thing in the gamezone header would be thegamezone_events_typeenum, which is only used by gamezone and helpers anyway, so that can safely move and we can delete the entire file. To make that enum name more generic I'll rename it in the move fromgamezone_events_typetolwmi_event_type(the enum isn't directly referenced anywhere anyway).
Quoted 5 lines
If that works for everyone I'll add one more patch to do the move & cleanup before "platform/x86: lenovo-wmi-other: Add
lwmi_attr_id()function" where I'm adding the .._NONE thermal mode. That will keep the purpose of each patch clean and avoid me needing to modify your patches too much.
That sounds good to me.
Moving everything from wmi_gamezone.h into wmi_helpers.h also seems more semantically correct from my perspective, since the former was just used to glue things together, which instead matches the purpose of the latter.
Thanks,
Rong
Quoted 6 lines
Thanks,
Derek.Quoted 2 lines
Thanks,
Rong
Derek J. Clark
maintainerRe: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting
In reply to Rong ZhangQuoted 172 lines · Rong Zhang
Hi Derek,
Quoted 12 lines · Derek John Clark
Quoted 11 lines · kernel test robot
Hi Derek,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc5 next-20260324]
[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]Quoted 5 lines
Quoted 5 lines
url: https://github.com/intel-lab-lkp/linux/commits/Derek-J-Clark/platform-x86-lenovo-wmi-other-Move-LWMI_FAN_DIV/20260325-070851 base: linus/master patch link: https://lore.kernel.org/r/20260324221032.1333636-9-derekjohn.clark%40gmail.com patch subject: [PATCH v5 8/8] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting config: x86_64-randconfig-005-20260325 (https://download.01.org/0day-ci/archive/20260326/[email protected]/config)
CONFIG_DMI=y
CONFIG_HWMON=y
CONFIG_FW_ATTR_CLASS=m
CONFIG_ACPI_BATTERY=m
CONFIG_ACPI_PLATFORM_PROFILE=y
CONFIG_ACPI_WMI=y
CONFIG_LENOVO_WMI_CAPDATA=m
CONFIG_LENOVO_WMI_EVENTS=y
CONFIG_LENOVO_WMI_HELPERS=y
CONFIG_LENOVO_WMI_GAMEZONE=y
CONFIG_LENOVO_WMI_TUNING=yThis isn't a legit config, as
CONFIG_LENOVO_WMI_TUNING=yshould have ensuredCONFIG_LENOVO_WMI_CAPDATA=y,CONFIG_ACPI_BATTERY=y, andCONFIG_FW_ATTR_CLASS=y.Quoted 45 lines
Quoted 45 lines
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260326/[email protected]/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
Quoted 2 lines
All errors (new ones prefixed by >>):
ld: vmlinux.o: in function `lwmi_om_fan_get_set':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:206:(.text+0x1b74542): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_attr_01_is_supported':
drivers/platform/x86/lenovo/wmi-other.c:1267:(.text+0x1b74fdf): undefined reference to `lwmi_attr_id'Quoted 2 lines
Quoted 2 lines
ld: drivers/platform/x86/lenovo/wmi-other.c:1270:(.text+0x1b75013): undefined reference to `lwmi_cd01_get_data'
ld: drivers/platform/x86/lenovo/wmi-other.c:1283:(.text+0x1b7515b): undefined reference to `lwmi_attr_id'ld: drivers/platform/x86/lenovo/wmi-other.c:1299:(.text+0x1b752f4): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd_fan':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:565:(.text+0x1b75ca3): undefined reference to `lwmi_cd_fan_get_data'
ld: vmlinux.o: in function `lwmi_psy_prop_is_writeable':
drivers/platform/x86/lenovo/wmi-other.c:687:(.text+0x1b75e2f): undefined reference to `lwmi_attr_id'Quoted 1 line
Quoted 1 line
ld: drivers/platform/x86/lenovo/wmi-other.c:690:(.text+0x1b75e5a): undefined reference to `lwmi_cd00_get_data'
ld: vmlinux.o: in function `lwmi_psy_ext_set_prop':
drivers/platform/x86/lenovo/wmi-other.c:649:(.text+0x1b75f9b): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_psy_ext_get_prop':
drivers/platform/x86/lenovo/wmi-other.c:603:(.text+0x1b761aa): undefined reference to `lwmi_attr_id'
ld: vmlinux.o: in function `lwmi_other_probe':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1612:(.text+0x1b764eb): undefined reference to `lwmi_cd_match_add_all'
ld: vmlinux.o: in function `lwmi_om_fan_info_collect_cd00':
drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b7680f): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:540:(.text+0x1b76838): undefined reference to `lwmi_cd00_get_data' ld: vmlinux.o: in function `lwmi_om_ps_ext_init':Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:806:(.text+0x1b76a57): undefined reference to `devm_battery_hook_register'
ld: vmlinux.o: in function `lwmi_om_fw_attr_add':
Quoted 1 line
Quoted 1 line
drivers/platform/x86/lenovo/wmi-other.c:1474:(.text+0x1b76afa): undefined reference to `firmware_attributes_class'
ld: vmlinux.o: in function `attr_current_value_show':
drivers/platform/x86/lenovo/wmi-other.c:1225:(.text+0x1b77015): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_current_value_store': drivers/platform/x86/lenovo/wmi-other.c:1165:(.text+0x1b776e2): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1168:(.text+0x1b7771c): undefined reference to `lwmi_cd01_get_data' ld: drivers/platform/x86/lenovo/wmi-other.c:1179:(.text+0x1b7781e): undefined reference to `lwmi_attr_id' ld: vmlinux.o: in function `attr_capdata01_show': drivers/platform/x86/lenovo/wmi-other.c:1099:(.text+0x1b77e38): undefined reference to `lwmi_attr_id' ld: drivers/platform/x86/lenovo/wmi-other.c:1102:(.text+0x1b77e67): undefined reference to `lwmi_cd01_get_data'Quoted 2 lines
Quoted 2 lines
Kconfigwarnings: (for reference only)
WARNING: unmet direct dependencies detected forLENOVO_WMI_TUNINGWhen randconfig selects symbols, some are selected by the randomizer, while some are selected by
Kconfigselect SYMBOL'. In this lkp test, CONFIG_LENOVO_WMI_GAMEZONE=y was selected by the randomizer, while CONFIG_LENOVO_WMI_TUNING=y was selected byselectLENOVO_WMI_TUNING' in `configLENOVO_WMI_GAMEZONE'.
Documentation/kbuild/kconfig-language.rstsays "select will force a symbol to a value without visiting the dependencies", resulting in unmet dependencies in this test and
https://lore.kernel.org/r/[email protected]Quoted 49 lines
Quoted 49 lines
Depends on [m]:
X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] &&ACPI_BATTERY[=m] Selected by [y]:
-LENOVO_WMI_GAMEZONE[=y] &&X86_PLATFORM_DEVICES[=y] &&ACPI_WMI[=y] && DMI [=y]vim +206
drivers/platform/x86/lenovo/wmi-other.c51ed34282f63fa Rong Zhang 2026-01-21 186 51ed34282f63fa Rong Zhang 2026-01-21 187 /** 51ed34282f63fa Rong Zhang 2026-01-21 188 * lwmi_om_fan_get_set() - Get or set fan RPM value of specified fan 51ed34282f63fa Rong Zhang 2026-01-21 189 * @priv: Driver private data structure 51ed34282f63fa Rong Zhang 2026-01-21 190 * @channel: Fan channel index (0-based) 51ed34282f63fa Rong Zhang 2026-01-21 191 * @val: Pointer to value (input for set, output for get) 51ed34282f63fa Rong Zhang 2026-01-21 192 * @set: True to set value, false to get value 51ed34282f63fa Rong Zhang 2026-01-21 193 * 51ed34282f63fa Rong Zhang 2026-01-21 194 * Communicates with WMI interface to either retrieve current fan RPM 51ed34282f63fa Rong Zhang 2026-01-21 195 * or set target fan RPM. 51ed34282f63fa Rong Zhang 2026-01-21 196 * 51ed34282f63fa Rong Zhang 2026-01-21 197 * Return: 0 on success, or an error code. 51ed34282f63fa Rong Zhang 2026-01-21 198 */ 51ed34282f63fa Rong Zhang 2026-01-21 199 static int lwmi_om_fan_get_set(struct lwmi_om_priv *priv, int channel, u32 *val, bool set) 51ed34282f63fa Rong Zhang 2026-01-21 200 { 51ed34282f63fa Rong Zhang 2026-01-21 201 struct wmi_method_args_32 args; 51ed34282f63fa Rong Zhang 2026-01-21 202 u32 method_id, retval; 51ed34282f63fa Rong Zhang 2026-01-21 203 int err; 51ed34282f63fa Rong Zhang 2026-01-21 204 51ed34282f63fa Rong Zhang 2026-01-21 205 method_id = set ? LWMI_FEATURE_VALUE_SET : LWMI_FEATURE_VALUE_GET; 51ed34282f63fa Rong Zhang 2026-01-21 @206 args.arg0 = LWMI_ATTR_ID_FAN_RPM(channel); 51ed34282f63fa Rong Zhang 2026-01-21 207 args.arg1 = set ? *val : 0; 51ed34282f63fa Rong Zhang 2026-01-21 208 51ed34282f63fa Rong Zhang 2026-01-21 209 err = lwmi_dev_evaluate_int(priv->wdev, 0x0, method_id, 51ed34282f63fa Rong Zhang 2026-01-21 210 (unsigned char *)&args, sizeof(args), &retval); 51ed34282f63fa Rong Zhang 2026-01-21 211 if (err) 51ed34282f63fa Rong Zhang 2026-01-21 212 return err; 51ed34282f63fa Rong Zhang 2026-01-21 213 51ed34282f63fa Rong Zhang 2026-01-21 214 if (!set) { 51ed34282f63fa Rong Zhang 2026-01-21 215 *val = retval; 51ed34282f63fa Rong Zhang 2026-01-21 216 return 0; 51ed34282f63fa Rong Zhang 2026-01-21 217 } 51ed34282f63fa Rong Zhang 2026-01-21 218 51ed34282f63fa Rong Zhang 2026-01-21 219 /* 51ed34282f63fa Rong Zhang 2026-01-21 220 * It seems that 0 means "no error" and 1 means "done". Apparently 51ed34282f63fa Rong Zhang 2026-01-21 221 * different firmware teams have different thoughts on indicating 51ed34282f63fa Rong Zhang 2026-01-21 222 * success, so we accepts both. 51ed34282f63fa Rong Zhang 2026-01-21 223 */ 51ed34282f63fa Rong Zhang 2026-01-21 224 return (retval == 0 || retval == 1) ? 0 : -EIO; 51ed34282f63fa Rong Zhang 2026-01-21 225 } 51ed34282f63fa Rong Zhang 2026-01-21 226Quoted 7 lines
Quoted 3 lines
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wikiCan someone explain to me why this is happening? I cannot reproduce these locally with W=1 and/or C=1. I'd prefer to resolve this before submitting a v6.
The issue exists since commit
6e38b9fcbfa3('platform/x86: lenovo:
gamezone needs "other mode"'). It might be a coincidence that lkp didn't running into a similar issue before. IMO `selectLENOVO_WMI_TUNING' shouldn't be used in the first place sinceLENOVO_WMI_TUNINGhas numerous dependencies.To fix this, we need to decouple lenovo-wmi-gamezone and lenovo-wmi- other by moving the notifier chain into lenovo-wmi-helpers. I will reply with a patch soon. Fell free to integrate it into your series.
Note that I couldn't completely test my patch since the lack of gamezone support on my device.
Quoted 9 lines
BTW, the fix patch has conflicts with my debugfs series since both touch lenovo-wmi-helpers. If you decide to integrate the fix patch into your series, could you integrate the debugfs series into yours too? The conflicts are trivial and contextual. You can resolve them yourself if you don't mind it ;-)
Thanks,
Rong
Absolutely, that's a good plan. If you want, send the new patch to me directly. Also, please leave a note on that other series in case Ilpo doesn't see this first.
And thanks for the clear explanation. Hopefully it all works like we expect.
Cheers,
Derek
Quoted 3 lines
Quoted 3 lines
Thanks,
Derek
Hi Derek,
There are typos in the patch titles (this and subsequent patches).
s#platform-x86#platform/x86#g
Quoted 25 lines · Derek J. Clark
This series adds many much needed features and fixes to the lenovo-wmi drivers.
Patch 1 moves
LWMI_FAN_DIVto be next to the rest of the fan attribute defines in preparation for adding additional attrbiute macros. This is so the attribute macros can all be in the same place in the file.Patch 2 cleans up
tunable_attr_01by removing an unused pointer and correctly assigning the members as u8 isntead of u32.Patch 3 adds a function to make assigning attribute ID's for capdata cleaner and easier.
Patch 4 addresses bugs where devices that don't support exposed attributes would still create the attribute, and also attempts to identify the correct capdata and set/get methods as some legacy interfaces don't use the custom mode in the method or capdata ID.
Patch 5 adds the remaining CPU attributes that weren't previously exposed.
Patch 6 adds GPU attributes.
Patch 7 renames a name constant in preparation for patch 6.
Quoted 7 lines
Patch 8 adds battery charge-type limiting when supported only by WMI, or when a module parameter to skip this check is set. The
MODULE_PARM_DESCmacro creates one check and two warnings in checkpatch. I reviewed other examples from the kernel and I am following the same convention, so I left it as is.Signed-off-by Derek J. Clark <[email protected]>
The series LGTM generally, thanks!
There are some tiny issues though, see my replies to the corresponding patches.
With them fixed, for the whole series:
My device doesn't support any CPU, GPU or PSU attributes, so for patch 1-4 and 7:
Thanks,
Rong
Quoted 58 lines
---
v5:
- Remove cv/cd_mode_id references that occured before patch 4.
- Movelwmi_attr_idtocapdata.cwith a namespace export.
- Fix mixing include.
- Makelwmi_attr_is_supportedreturn bool.
- Use switch instead of if for setting/getting charge type state.
- Various formatting fixes.
v4: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Use loop instead of back gotos for identifying the working attributeID.- Use function instead of macro to assign
attribute_id, preserving
types.
- Removed unused defines and enum values.
- Rename charging defines to clarify thier purpose.
- Fixed various formatting issues from v3.
- Added module param to skip ACPI check when loading the driver for
the power supply extension.
- Don't abort adding power supply extension if the ACPI handle from
ideapad is not present.
- Don't worry about symmetric cleanup when cleaning up attributes in
an error state.
- Reword Patch 8 commit message to be more concise.
- Fix wording in Patch 7 to match the changes.
v3: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Re-add HWMON name const and just renameLWMI_OM_FW_ATTR_BASE_PATH
- Fix linker warnings by moving acpi/battery include to the end of the
list.
- Remove CPU/GPU OC features. These attributes are BOOL type and will
need a new constructor that I'll add later.
v2: https://lore.kernel.org/platform-driver-x86/[email protected]/
- Fixgpu_modemisisng from attributes list.
- Fix prototypes for power suppy patch.
- Reorganize CPU and GPU attributes alphabetically.
- Break out the patch consolidating the driver name cost.
- Move some of the refactoring ofattribute_idback to into patch 1
where it belongs.
- Fix some additional typos in function prototypes.
v1: https://lore.kernel.org/platform-driver-x86/[email protected]/Derek J. Clark (8):
platform-x86: lenovo-wmi-other: MoveLWMI_FAN_DIV
platform-x86: lenovo-wmi-other: Fixtunable_attr_01struct members platform/x86: lenovo-wmi-other: Addlwmi_attr_id()function platform/x86: lenovo-wmi-other: Limit adding attributes to supported
devices
platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes platform/x86: lenovo-wmi-other: Add GPU tunable attributes
platform-x86: lenovo-wmi-other: RenameLWMI_OM_FW_ATTR_BASE_PATHplatform/x86: lenovo-wmi-other: Add WMI battery charge limiting.../wmi/devices/lenovo-wmi-other.rst | 19 + drivers/platform/x86/lenovo/Kconfig | 1 + drivers/platform/x86/lenovo/wmi-capdata.c | 25 +- drivers/platform/x86/lenovo/wmi-capdata.h | 10 +- drivers/platform/x86/lenovo/wmi-gamezone.h | 1 + drivers/platform/x86/lenovo/wmi-other.c | 586 ++++++++++++++++-- 6 files changed, 596 insertions(+), 46 deletions(-)