X86 platform drivers
 help / color / mirror / Atom feed
* [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement
@ 2026-02-13  8:02 Derek J. Clark
  2026-02-13  8:02 ` [PATCH 1/5] platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro Derek J. Clark
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

This series adds many much needed features and fixes to the lenovo-wmi
drivers.

Patch 1 adds a macro to make assigning attribute ID's for capdata
cleaner and easier.
Patch 2 addresses a bug 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 3 adds the remaining CPU attributes that weren't previously
exposed.
Patch 4 adds the GPU attributes that weren't previously exposed.
Patch 5 adds battery charge-type limiting when supported by WMI.

After applying Rong's series from
https://lore.kernel.org/platform-driver-x86/20260210191938.137234-1-i@rong.moe/
I found that there weren't any conflicts, so rather than combine
the series we can just review each separately.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>

Derek J. Clark (5):
  platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro
  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: Add WMI battery charge limiting.

 .../wmi/devices/lenovo-wmi-other.rst          |  21 +
 drivers/platform/x86/lenovo/wmi-capdata.h     |  13 +-
 drivers/platform/x86/lenovo/wmi-gamezone.h    |   1 +
 drivers/platform/x86/lenovo/wmi-other.c       | 605 ++++++++++++++++--
 4 files changed, 591 insertions(+), 49 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/5] platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro
  2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
@ 2026-02-13  8:02 ` Derek J. Clark
  2026-02-13  8:02 ` [PATCH 2/5] platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices Derek J. Clark
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

Adds LWMI_ATTR_ID macro. In the same vein as LWMI_ATTR_ID_FAN_RPM,
but as a generic, to de-duplicate attribute_id assignment biolerplate.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/platform/x86/lenovo/wmi-capdata.h  |  6 ++++
 drivers/platform/x86/lenovo/wmi-gamezone.h |  1 +
 drivers/platform/x86/lenovo/wmi-other.c    | 32 ++++++----------------
 3 files changed, 16 insertions(+), 23 deletions(-)

diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index 8c1df3efcc553..27202e2dc8a59 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -17,6 +17,12 @@
 #define LWMI_ATTR_MODE_ID_MASK	GENMASK(15, 8)
 #define LWMI_ATTR_TYPE_ID_MASK	GENMASK(7, 0)
 
+#define LWMI_ATTR_ID(dev, feat, mode, type) \
+	(FIELD_PREP(LWMI_ATTR_DEV_ID_MASK, dev) | \
+	 FIELD_PREP(LWMI_ATTR_FEAT_ID_MASK, feat) | \
+	 FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) | \
+	 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, type))
+
 #define LWMI_DEVICE_ID_FAN	0x04
 
 struct component_match;
diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.h b/drivers/platform/x86/lenovo/wmi-gamezone.h
index 6b163a5eeb959..ddb919cf6c36d 100644
--- a/drivers/platform/x86/lenovo/wmi-gamezone.h
+++ b/drivers/platform/x86/lenovo/wmi-gamezone.h
@@ -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,
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index 6040f45aa2b0d..559feb49c9f11 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -71,10 +71,9 @@
 #define LWMI_FAN_NR 4
 #define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
 
-#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_FAN_DIV 100
 
@@ -716,12 +715,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)
@@ -787,11 +782,8 @@ 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);
+	attribute_id = 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);
 	if (ret)
@@ -838,7 +830,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;
 
@@ -846,13 +837,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),
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/5] platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices
  2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
  2026-02-13  8:02 ` [PATCH 1/5] platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro Derek J. Clark
@ 2026-02-13  8:02 ` Derek J. Clark
  2026-02-13  8:02 ` [PATCH 3/5] platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes Derek J. Clark
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

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).
- Similarly, 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.

While adding members to tunable_attr_01, remove unused capdata pointer
and limit size of all ID's to the appropriate size.

Reported-by: Kurt Borja <kuurtb@gmail.com>
Closes: https://lore.kernel.org/platform-driver-x86/DG60P3SHXR8H.3NSEHMZ6J7XRC@gmail.com/
Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/platform/x86/lenovo/wmi-other.c | 123 ++++++++++++++++++++----
 1 file changed, 104 insertions(+), 19 deletions(-)

diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index 559feb49c9f11..f3f12303e3798 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -545,11 +545,12 @@ 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;
+	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 = {
@@ -716,7 +717,7 @@ static ssize_t attr_capdata01_show(struct kobject *kobj,
 	int value, ret;
 
 	attribute_id = LWMI_ATTR_ID(tunable_attr->device_id, tunable_attr->feature_id,
-				    LWMI_GZ_THERMAL_MODE_CUSTOM, tunable_attr->type_id);
+				    tunable_attr->cd_mode_id, tunable_attr->type_id);
 
 	ret = lwmi_cd01_get_data(priv->cd01_list, attribute_id, &capdata);
 	if (ret)
@@ -771,7 +772,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;
 
@@ -782,10 +782,10 @@ static ssize_t attr_current_value_store(struct kobject *kobj,
 	if (mode != LWMI_GZ_THERMAL_MODE_CUSTOM)
 		return -EBUSY;
 
-	attribute_id = LWMI_ATTR_ID(tunable_attr->device_id, tunable_attr->feature_id,
-				    mode, tunable_attr->type_id);
+	args.arg0 = LWMI_ATTR_ID(tunable_attr->device_id, tunable_attr->feature_id,
+				 tunable_attr->cd_mode_id, 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;
 
@@ -796,7 +796,8 @@ 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.arg0 = LWMI_ATTR_ID(tunable_attr->device_id, tunable_attr->feature_id,
+				 tunable_attr->cv_mode_id, tunable_attr->type_id);
 	args.arg1 = value;
 
 	ret = lwmi_dev_evaluate_int(priv->wdev, 0x0, LWMI_FEATURE_VALUE_SET,
@@ -830,13 +831,16 @@ 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;
-	int retval;
-	int ret;
+	int retval, ret;
 
 	ret = lwmi_om_notifier_call(&mode);
 	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);
 
@@ -849,6 +853,85 @@ 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: Support level, or an error code.
+ */
+static int lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
+{
+	struct lwmi_om_priv *priv = dev_get_drvdata(tunable_attr->dev);
+	u8 mode = LWMI_GZ_THERMAL_MODE_CUSTOM;
+	struct wmi_method_args_32 args;
+	struct capdata01 capdata;
+	int retval, ret;
+
+	/* Determine tunable_attr->cd_mode_id */
+no_mode_fallback_1:
+	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, args.arg0, &capdata);
+	if (ret && mode) {
+		dev_dbg(tunable_attr->dev, "Attribute id %x not supported\n", args.arg0);
+		mode = LWMI_GZ_THERMAL_MODE_NONE;
+		goto no_mode_fallback_1;
+	}
+	if (ret)
+		goto not_supported;
+	if (!capdata.supported) {
+		ret = -EOPNOTSUPP;
+		goto not_supported;
+	}
+
+	tunable_attr->cd_mode_id = mode;
+
+	/* Determine tunable_attr->cv_mode_id */
+	mode = LWMI_GZ_THERMAL_MODE_CUSTOM;
+no_mode_fallback_2:
+	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),
+				    &retval);
+	if ((ret && mode) || (!retval && mode)) {
+		dev_dbg(tunable_attr->dev, "Attribute id %x not supported\n", args.arg0);
+		mode = LWMI_GZ_THERMAL_MODE_NONE;
+		goto no_mode_fallback_2;
+	}
+	if (ret)
+		goto not_supported;
+	if (retval == 0) {
+		ret = -EOPNOTSUPP;
+		goto not_supported;
+	}
+
+	tunable_attr->cv_mode_id = mode;
+	dev_dbg(tunable_attr->dev, "cd_mode_id: %02x%02x%02x%02x, cv_mode_id: %#08x attribute support level: %x\n",
+		tunable_attr->device_id, tunable_attr->feature_id, tunable_attr->cd_mode_id,
+		tunable_attr->type_id, args.arg0, capdata.supported);
+
+	return capdata.supported;
+
+not_supported:
+	dev_dbg(tunable_attr->dev, "Attribute id %x not supported\n", args.arg0);
+	return ret;
+}
+
 /* Lenovo WMI Other Mode Attribute macros */
 #define __LWMI_ATTR_RO(_func, _name)                                  \
 	{                                                             \
@@ -972,19 +1055,21 @@ static int lwmi_om_fw_attr_add(struct lwmi_om_priv *priv)
 	}
 
 	for (i = 0; i < ARRAY_SIZE(cd01_attr_groups) - 1; i++) {
-		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;
+		if (lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr) > 0) {
+			err = sysfs_create_group(&priv->fw_attr_kset->kobj,
+						 cd01_attr_groups[i].attr_group);
+			if (err)
+				goto err_remove_groups;
+		}
 	}
 	return 0;
 
 err_remove_groups:
 	while (i--)
-		sysfs_remove_group(&priv->fw_attr_kset->kobj,
-				   cd01_attr_groups[i].attr_group);
+		if (lwmi_attr_01_is_supported(cd01_attr_groups[i].tunable_attr) > 0)
+			sysfs_remove_group(&priv->fw_attr_kset->kobj,
+					   cd01_attr_groups[i].attr_group);
 
 	kset_unregister(priv->fw_attr_kset);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/5] platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes
  2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
  2026-02-13  8:02 ` [PATCH 1/5] platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro Derek J. Clark
  2026-02-13  8:02 ` [PATCH 2/5] platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices Derek J. Clark
@ 2026-02-13  8:02 ` Derek J. Clark
  2026-02-13  8:02 ` [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU " Derek J. Clark
  2026-02-13  8:02 ` [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting Derek J. Clark
  4 siblings, 0 replies; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

Use an enum for all device Id's and CPU attribute feature ID's,
add missing CPU attributes.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 .../wmi/devices/lenovo-wmi-other.rst          |  10 ++
 drivers/platform/x86/lenovo/wmi-capdata.h     |   5 +-
 drivers/platform/x86/lenovo/wmi-other.c       | 108 +++++++++++++++++-
 3 files changed, 117 insertions(+), 6 deletions(-)

diff --git a/Documentation/wmi/devices/lenovo-wmi-other.rst b/Documentation/wmi/devices/lenovo-wmi-other.rst
index 01d4711567380..f4763ed66cc6d 100644
--- a/Documentation/wmi/devices/lenovo-wmi-other.rst
+++ b/Documentation/wmi/devices/lenovo-wmi-other.rst
@@ -68,9 +68,19 @@ Each attribute has the following properties:
  - type
 
 The following firmware-attributes are implemented:
+ - cpu_oc_stat: CPU Overlocking Status
+ - 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
 -------------------------
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index 27202e2dc8a59..aa48f43cbb43b 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -23,7 +23,10 @@
 	 FIELD_PREP(LWMI_ATTR_MODE_ID_MASK, mode) | \
 	 FIELD_PREP(LWMI_ATTR_TYPE_ID_MASK, type))
 
-#define LWMI_DEVICE_ID_FAN	0x04
+enum lwmi_device_id {
+	LWMI_DEVICE_ID_CPU = 0x01,
+	LWMI_DEVICE_ID_FAN = 0x04,
+};
 
 struct component_match;
 struct device;
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index f3f12303e3798..7713a096077dd 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -54,15 +54,22 @@
 
 #define LENOVO_OTHER_MODE_GUID "DC2A8805-3A8C-41BA-A6F7-092E0089CD3B"
 
-#define LWMI_DEVICE_ID_CPU 0x01
-
-#define LWMI_FEATURE_ID_CPU_SPPT 0x01
-#define LWMI_FEATURE_ID_CPU_SPL 0x02
-#define LWMI_FEATURE_ID_CPU_FPPT 0x03
+enum lwmi_feature_id_cpu {
+	LWMI_FEATURE_ID_CPU_SPPT = 0x01,
+	LWMI_FEATURE_ID_CPU_SPL = 0x02,
+	LWMI_FEATURE_ID_CPU_FPPT = 0x03,
+	LWMI_FEATURE_ID_CPU_TEMP = 0x04,
+	LWMI_FEATURE_ID_CPU_APU = 0x05,
+	LWMI_FEATURE_ID_CPU_CL = 0x06,
+	LWMI_FEATURE_ID_CPU_TAU = 0x07,
+	LWMI_FEATURE_ID_CPU_OC = 0x08,
+	LWMI_FEATURE_ID_CPU_IPL = 0x09,
+};
 
 #define LWMI_FEATURE_ID_FAN_RPM 0x03
 
 #define LWMI_TYPE_ID_NONE 0x00
+#define LWMI_TYPE_ID_CROSSLOAD 0x01
 
 #define LWMI_FEATURE_VALUE_GET 17
 #define LWMI_FEATURE_VALUE_SET 18
@@ -559,18 +566,78 @@ static struct tunable_attr_01 ppt_pl1_spl = {
 	.type_id = LWMI_TYPE_ID_NONE,
 };
 
+static struct tunable_attr_01 ppt_pl1_spl_cl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_SPL,
+	.type_id = LWMI_TYPE_ID_CROSSLOAD,
+};
+
 static struct tunable_attr_01 ppt_pl2_sppt = {
 	.device_id = LWMI_DEVICE_ID_CPU,
 	.feature_id = LWMI_FEATURE_ID_CPU_SPPT,
 	.type_id = LWMI_TYPE_ID_NONE,
 };
 
+static struct tunable_attr_01 ppt_pl2_sppt_cl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_SPPT,
+	.type_id = LWMI_TYPE_ID_CROSSLOAD,
+};
+
 static struct tunable_attr_01 ppt_pl3_fppt = {
 	.device_id = LWMI_DEVICE_ID_CPU,
 	.feature_id = LWMI_FEATURE_ID_CPU_FPPT,
 	.type_id = LWMI_TYPE_ID_NONE,
 };
 
+static struct tunable_attr_01 ppt_pl3_fppt_cl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_FPPT,
+	.type_id = LWMI_TYPE_ID_CROSSLOAD,
+};
+
+static struct tunable_attr_01 cpu_temp = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_TEMP,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 ppt_pl1_apu_spl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_APU,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 ppt_cpu_cl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_CL,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 ppt_pl1_tau = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_TAU,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 cpu_oc_stat = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_OC,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 ppt_pl4_ipl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_IPL,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 ppt_pl4_ipl_cl = {
+	.device_id = LWMI_DEVICE_ID_CPU,
+	.feature_id = LWMI_FEATURE_ID_CPU_IPL,
+	.type_id = LWMI_TYPE_ID_CROSSLOAD,
+};
+
 struct capdata01_attr_group {
 	const struct attribute_group *attr_group;
 	struct tunable_attr_01 *tunable_attr;
@@ -1011,15 +1078,46 @@ static int lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
 
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
 			      "Set the CPU sustained power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl_cl, "ppt_pl1_spl_cl",
+			      "Set the CPU cross loading sustained power limit");
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
 			      "Set the CPU slow package power tracking limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt_cl, "ppt_pl2_sppt_cl",
+			      "Set the CPU cross loading slow package power tracking limit");
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
 			      "Set the CPU fast package power tracking limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt_cl, "ppt_pl3_fppt_cl",
+			      "Set the CPU cross loading fast package power tracking limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_temp, "cpu_temp",
+			      "Set the CPU thermal load limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_apu_spl, "ppt_pl1_apu_spl",
+			      "Set the APU sustained power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_cpu_cl, "ppt_cpu_cl",
+			      "Set the CPU cross loading power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_tau, "ppt_pl1_tau",
+			      "Set the CPU sustained power limit exceed duration");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_oc_stat, "cpu_oc_stat",
+			      "Set the CPU overclocking status");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl, "ppt_pl4_ipl",
+			      "Set the CPU instantaneous power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl_cl, "ppt_pl4_ipl_cl",
+			      "Set the CPU cross loading instantaneous power limit");
+
 
 static struct capdata01_attr_group cd01_attr_groups[] = {
 	{ &ppt_pl1_spl_attr_group, &ppt_pl1_spl },
+	{ &ppt_pl1_spl_cl_attr_group, &ppt_pl1_spl_cl },
 	{ &ppt_pl2_sppt_attr_group, &ppt_pl2_sppt },
+	{ &ppt_pl2_sppt_cl_attr_group, &ppt_pl2_sppt_cl },
 	{ &ppt_pl3_fppt_attr_group, &ppt_pl3_fppt },
+	{ &ppt_pl3_fppt_cl_attr_group, &ppt_pl3_fppt_cl },
+	{ &cpu_temp_attr_group, &cpu_temp },
+	{ &ppt_pl1_apu_spl_attr_group, &ppt_pl1_apu_spl },
+	{ &ppt_cpu_cl_attr_group, &ppt_cpu_cl },
+	{ &ppt_pl1_tau_attr_group, &ppt_pl1_tau },
+	{ &cpu_oc_stat_attr_group, &cpu_oc_stat },
+	{ &ppt_pl4_ipl_attr_group, &ppt_pl4_ipl },
+	{ &ppt_pl4_ipl_cl_attr_group, &ppt_pl4_ipl_cl },
 	{},
 };
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU tunable attributes
  2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
                   ` (2 preceding siblings ...)
  2026-02-13  8:02 ` [PATCH 3/5] platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes Derek J. Clark
@ 2026-02-13  8:02 ` Derek J. Clark
  2026-02-13 19:26   ` kernel test robot
  2026-02-13 20:28   ` kernel test robot
  2026-02-13  8:02 ` [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting Derek J. Clark
  4 siblings, 2 replies; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

Use an enum for all GPU attribute feature ID's and add GPU attributes.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 .../wmi/devices/lenovo-wmi-other.rst          |  11 ++
 drivers/platform/x86/lenovo/wmi-capdata.h     |   1 +
 drivers/platform/x86/lenovo/wmi-other.c       | 114 ++++++++++++++++++
 3 files changed, 126 insertions(+)

diff --git a/Documentation/wmi/devices/lenovo-wmi-other.rst b/Documentation/wmi/devices/lenovo-wmi-other.rst
index f4763ed66cc6d..f7564b23bb7f0 100644
--- a/Documentation/wmi/devices/lenovo-wmi-other.rst
+++ b/Documentation/wmi/devices/lenovo-wmi-other.rst
@@ -70,6 +70,17 @@ Each attribute has the following properties:
 The following firmware-attributes are implemented:
  - cpu_oc_stat: CPU Overlocking Status
  - 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_oc_stat: GPU Overclocking Status
+ - 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
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index aa48f43cbb43b..b7f9ee7b301a5 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -25,6 +25,7 @@
 
 enum lwmi_device_id {
 	LWMI_DEVICE_ID_CPU = 0x01,
+	LWMI_DEVICE_ID_GPU = 0x02,
 	LWMI_DEVICE_ID_FAN = 0x04,
 };
 
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index 7713a096077dd..cc024cb369b0f 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -66,6 +66,20 @@ enum lwmi_feature_id_cpu {
 	LWMI_FEATURE_ID_CPU_IPL = 0x09,
 };
 
+enum lwmi_feature_id_gpu {
+	LWMI_FEATURE_ID_GPU_NV_PPAB = 0x01,
+	LWMI_FEATURE_ID_GPU_NV_CTGP = 0x02,
+	LWMI_FEATURE_ID_GPU_TEMP = 0x03,
+	LWMI_FEATURE_ID_GPU_AC_OFFSET = 0x04,
+	LWMI_FEATURE_ID_GPU_OC = 0x05,
+	LWMI_FEATURE_ID_DGPU_BOOST_CLK = 0x06,
+	LWMI_FEATURE_ID_DGPU_EN = 0x07,
+	LWMI_FEATURE_ID_GPU_MODE = 0x08,
+	LWMI_FEATURE_ID_DGPU_DIDVID = 0x09,
+	LWMI_FEATURE_ID_GPU_NV_BPL = 0x0a,
+	LWMI_FEATURE_ID_GPU_NV_CPU_BOOST = 0x0b,
+};
+
 #define LWMI_FEATURE_ID_FAN_RPM 0x03
 
 #define LWMI_TYPE_ID_NONE 0x00
@@ -638,6 +652,72 @@ static struct tunable_attr_01 ppt_pl4_ipl_cl = {
 	.type_id = LWMI_TYPE_ID_CROSSLOAD,
 };
 
+static struct tunable_attr_01 gpu_nv_ppab = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_NV_PPAB,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_nv_ctgp = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_NV_CTGP,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_temp = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_TEMP,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_nv_ac_offset = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_AC_OFFSET,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_oc_stat = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_OC,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 dgpu_boost_clk = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_DGPU_BOOST_CLK,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 dgpu_enable = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_DGPU_EN,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_mode = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_MODE,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 dgpu_didvid = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_DGPU_DIDVID,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_nv_bpl = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_NV_BPL,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
+static struct tunable_attr_01 gpu_nv_cpu_boost = {
+	.device_id = LWMI_DEVICE_ID_GPU,
+	.feature_id = LWMI_FEATURE_ID_GPU_NV_CPU_BOOST,
+	.type_id = LWMI_TYPE_ID_NONE,
+};
+
 struct capdata01_attr_group {
 	const struct attribute_group *attr_group;
 	struct tunable_attr_01 *tunable_attr;
@@ -1076,6 +1156,7 @@ static int lwmi_attr_01_is_supported(struct tunable_attr_01 *tunable_attr)
 		.name = _fsname, .attrs = _attrname##_attrs               \
 	}
 
+/* CPU tunable attributes */
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
 			      "Set the CPU sustained power limit");
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl_cl, "ppt_pl1_spl_cl",
@@ -1103,6 +1184,29 @@ LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl, "ppt_pl4_ipl",
 LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl_cl, "ppt_pl4_ipl_cl",
 			      "Set the CPU cross loading instantaneous power limit");
 
+/* GPU tunable attributes */
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ppab, "gpu_nv_ppab",
+			      "Set the Nvidia GPU power performance aware boost limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ctgp, "gpu_nv_ctgp",
+			      "Set the GPU configurable total graphics power");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_temp, "gpu_temp",
+			      "Set the GPU thermal load limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ac_offset, "gpu_nv_ac_offset",
+			      "Set the Nvidia GPU AC total processing power baseline offset");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_oc_stat, "gpu_oc_stat",
+			      "Set the GPU overclocking status");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_boost_clk, "gpu_boost_clk",
+			      "Set the dedicated GPU boost clock");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_enable, "dgpu_enable",
+			      "Set the dedicated Nvidia GPU enabled status");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_mode, "gpu_mode",
+			      "Set the GPU mode by power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_didvid, "gpu_didvid",
+			      "Get the GPU device identifier and vendor identifier");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_bpl, "gpu_nv_bpl",
+			      "Set the Nvidia GPU base power limit");
+LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_cpu_boost, "gpu_nv_cpu_boost",
+			      "Set the Nvidia GPU to CPU dynamic boost limit");
 
 static struct capdata01_attr_group cd01_attr_groups[] = {
 	{ &ppt_pl1_spl_attr_group, &ppt_pl1_spl },
@@ -1118,6 +1222,16 @@ static struct capdata01_attr_group cd01_attr_groups[] = {
 	{ &cpu_oc_stat_attr_group, &cpu_oc_stat },
 	{ &ppt_pl4_ipl_attr_group, &ppt_pl4_ipl },
 	{ &ppt_pl4_ipl_cl_attr_group, &ppt_pl4_ipl_cl },
+	{ &gpu_nv_ppab_attr_group, &gpu_nv_ppab },
+	{ &gpu_nv_ctgp_attr_group, &gpu_nv_ctgp },
+	{ &gpu_temp_attr_group, &gpu_temp },
+	{ &gpu_nv_ac_offset_attr_group, &gpu_nv_ac_offset },
+	{ &gpu_oc_stat_attr_group, &gpu_oc_stat },
+	{ &dgpu_boost_clk_attr_group, &dgpu_boost_clk },
+	{ &dgpu_enable_attr_group, &dgpu_enable },
+	{ &dgpu_didvid_attr_group, &dgpu_didvid },
+	{ &gpu_nv_bpl_attr_group, &gpu_nv_bpl },
+	{ &gpu_nv_cpu_boost_attr_group, &gpu_nv_cpu_boost },
 	{},
 };
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting.
  2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
                   ` (3 preceding siblings ...)
  2026-02-13  8:02 ` [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU " Derek J. Clark
@ 2026-02-13  8:02 ` Derek J. Clark
  2026-02-13 22:59   ` kernel test robot
  4 siblings, 1 reply; 9+ messages in thread
From: Derek J. Clark @ 2026-02-13  8:02 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: Mark Pearson, Armin Wolf, Jonathan Corbet, Rong Zhang, Kurt Borja,
	Derek J . Clark, platform-driver-x86, linux-kernel

Add charge-type power supply extension for devices that support WMI based
charge enable/disable. Lenovo Legion devices that implement function ID
and capdata 00 ID 0x03010001 are able to enable or disable charging
through the lenovo-wmi-other interface. The ideapad_laptop driver
conflicts with this if it can also provide the attribute, so we have to
get the acpi_handle and check for the same ACPI methods that enable the
feature in that driver. The ACPI method is more reliable from my testing
when both are present, so there is no need to modify the ideapad_laptop
driver instead.

The power supply extension requires a name. Instead of adding a third
const macro with the same information, replace LWMI_OM_FW_ATTR_BASE_PATH
and LWMI_OM_HWMON_NAME with LWMI_OM_NAME and use that everywhere.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
---
 drivers/platform/x86/lenovo/wmi-capdata.h |   1 +
 drivers/platform/x86/lenovo/wmi-other.c   | 238 +++++++++++++++++++++-
 2 files changed, 233 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/lenovo/wmi-capdata.h b/drivers/platform/x86/lenovo/wmi-capdata.h
index b7f9ee7b301a5..00471551e7d60 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.h
+++ b/drivers/platform/x86/lenovo/wmi-capdata.h
@@ -26,6 +26,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,
 };
 
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
index cc024cb369b0f..a1a0638d5ce77 100644
--- a/drivers/platform/x86/lenovo/wmi-other.c
+++ b/drivers/platform/x86/lenovo/wmi-other.c
@@ -26,6 +26,7 @@
  *   - binding to Capability Data 00 and Fan
  */
 
+#include <acpi/battery.h>
 #include <linux/acpi.h>
 #include <linux/bitfield.h>
 #include <linux/cleanup.h>
@@ -42,6 +43,7 @@
 #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>
 
@@ -80,10 +82,17 @@ enum lwmi_feature_id_gpu {
 	LWMI_FEATURE_ID_GPU_NV_CPU_BOOST = 0x0b,
 };
 
+enum lwmi_feature_id_psu {
+	LWMI_FEATURE_ID_PSU_INSTANT_MODE = 0x01,
+	LWMI_FEATURE_ID_PSU_CHARGE_MODE = 0x02,
+};
+
 #define LWMI_FEATURE_ID_FAN_RPM 0x03
 
 #define LWMI_TYPE_ID_NONE 0x00
 #define LWMI_TYPE_ID_CROSSLOAD 0x01
+#define LWMI_TYPE_ID_PSU_AC 0x01
+#define LWMI_TYPE_ID_PSU_PD 0x02
 
 #define LWMI_FEATURE_VALUE_GET 17
 #define LWMI_FEATURE_VALUE_SET 18
@@ -91,15 +100,20 @@ enum lwmi_feature_id_gpu {
 #define LWMI_FAN_ID_BASE 1
 #define LWMI_FAN_NR 4
 #define LWMI_FAN_ID(x) ((x) + LWMI_FAN_ID_BASE)
+#define LWMI_FAN_DIV 100
+
+#define LWMI_CHARGE_MODE_ENABLED	0x00
+#define LWMI_CHARGE_MODE_DISABLED	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_FAN_DIV 100
+#define LWMI_ATTR_ID_PSU(feat, type)		\
+	LWMI_ATTR_ID(LWMI_DEVICE_ID_PSU, feat,		\
+		     LWMI_GZ_THERMAL_MODE_NONE, type)
 
-#define LWMI_OM_FW_ATTR_BASE_PATH "lenovo-wmi-other"
-#define LWMI_OM_HWMON_NAME "lenovo_wmi_other"
+#define LWMI_OM_NAME "lenovo-wmi-other"
 
 static BLOCKING_NOTIFIER_HEAD(om_chain_head);
 static DEFINE_IDA(lwmi_om_ida);
@@ -139,6 +153,8 @@ struct lwmi_om_priv {
 		bool capdata00_collected : 1;
 		bool capdata_fan_collected : 1;
 	} fan_flags;
+
+	struct acpi_battery_hook battery_hook;
 };
 
 /*
@@ -454,7 +470,7 @@ static void lwmi_om_hwmon_add(struct lwmi_om_priv *priv)
 	}
 
 	priv->hwmon_dev = hwmon_device_register_with_info(&priv->wdev->dev,
-							  LWMI_OM_HWMON_NAME, priv,
+							  LWMI_OM_NAME, priv,
 							  &lwmi_om_hwmon_chip_info,
 							  NULL);
 	if (IS_ERR(priv->hwmon_dev)) {
@@ -563,6 +579,216 @@ 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_prop_is_writeable() - 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
+ *
+ * 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 *data,
+				 enum power_supply_property prop,
+				 union power_supply_propval *val)
+{
+	struct lwmi_om_priv *priv = data;
+	struct wmi_method_args_32 args;
+	u32 retval;
+	int ret;
+
+	args.arg0 = LWMI_ATTR_ID_PSU(LWMI_FEATURE_ID_PSU_INSTANT_MODE, 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);
+
+	if (retval == LWMI_CHARGE_MODE_DISABLED)
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_LONGLIFE;
+	else
+		val->intval = POWER_SUPPLY_CHARGE_TYPE_STANDARD;
+
+	return 0;
+}
+
+/**
+ * lwmi_psy_prop_is_writeable() - 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_INSTANT_MODE, LWMI_TYPE_ID_PSU_AC);
+	if (val->intval == POWER_SUPPLY_CHARGE_TYPE_LONGLIFE)
+		args.arg1 = LWMI_CHARGE_MODE_DISABLED;
+	else
+		args.arg1 = LWMI_CHARGE_MODE_ENABLED;
+
+	dev_dbg(&priv->wdev->dev, "Attempting to set %#08x for property %x to %x\n",
+		args.arg0, prop, args.arg1);
+
+	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;
+	struct capdata00 capdata;
+	u32 attribute_id = LWMI_ATTR_ID_PSU(LWMI_FEATURE_ID_PSU_INSTANT_MODE, 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 (%#08x) support level: %x\n",
+		attribute_id, capdata.supported);
+
+	return capdata.supported;
+}
+
+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_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
+ * @acpi_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,
+ * thenm 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)
+{
+	if (!handle)
+		return AE_OK;
+
+	acpi_handle *ahand = context;
+	*ahand = handle;
+
+	return AE_CTRL_TERMINATE;
+}
+
+/**
+ * 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,
+ * thenm if not, hooks the battery to our WMI methods.
+ */
+static void lwmi_om_ps_ext_init(struct lwmi_om_priv *priv)
+{
+	static const char * const ideapad_hid = "VPC2004";
+	acpi_handle handle = NULL;
+	int ret;
+
+	/* Deconflict ideapad_laptop driver */
+	ret = acpi_get_devices(ideapad_hid, lwmi_acpi_match, &handle, NULL);
+	if (ret)
+		return;
+
+	if (!handle)
+		return;
+
+	if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC")) {
+		dev_dbg(&priv->wdev->dev, "ideapad_laptop driver manages battery for device.\n");
+		return;
+	}
+
+	/* 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 {
@@ -1252,8 +1478,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_NAME, priv->ida_id);
 	if (IS_ERR(priv->fw_attr_dev)) {
 		err = PTR_ERR(priv->fw_attr_dev);
 		goto err_free_ida;
@@ -1345,6 +1570,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);
 }
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU tunable attributes
  2026-02-13  8:02 ` [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU " Derek J. Clark
@ 2026-02-13 19:26   ` kernel test robot
  2026-02-13 20:28   ` kernel test robot
  1 sibling, 0 replies; 9+ messages in thread
From: kernel test robot @ 2026-02-13 19:26 UTC (permalink / raw)
  To: Derek J. Clark, Ilpo Järvinen, Hans de Goede
  Cc: llvm, oe-kbuild-all, Mark Pearson, Armin Wolf, Jonathan Corbet,
	Rong Zhang, Kurt Borja, Derek J . Clark, platform-driver-x86,
	linux-kernel

Hi Derek,

kernel test robot noticed the following build warnings:

[auto build test WARNING on next-20260212]
[cannot apply to linus/master v6.19 v6.19-rc8 v6.19-rc7 v6.19]
[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-Add-LWMI_ATTR_ID-Macro/20260213-161603
base:   next-20260212
patch link:    https://lore.kernel.org/r/20260213081243.794288-5-derekjohn.clark%40gmail.com
patch subject: [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU tunable attributes
config: x86_64-randconfig-011-20260214 (https://download.01.org/0day-ci/archive/20260214/202602140321.pfFQKWKX-lkp@intel.com/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/20260214/202602140321.pfFQKWKX-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602140321.pfFQKWKX-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/lenovo/wmi-other.c:1202:1: warning: unused variable 'gpu_mode_attr_group' [-Wunused-const-variable]
    1202 | LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_mode, "gpu_mode",
         | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1203 |                               "Set the GPU mode by power limit");
         |                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/platform/x86/lenovo/wmi-other.c:1155:38: note: expanded from macro 'LWMI_ATTR_GROUP_TUNABLE_CAP01'
    1155 |         static const struct attribute_group _attrname##_attr_group = {    \
         |                                             ^~~~~~~~~~~~~~~~~~~~~~
   <scratch space>:155:1: note: expanded from here
     155 | gpu_mode_attr_group
         | ^~~~~~~~~~~~~~~~~~~
   1 warning generated.


vim +/gpu_mode_attr_group +1202 drivers/platform/x86/lenovo/wmi-other.c

  1081	
  1082	/* Lenovo WMI Other Mode Attribute macros */
  1083	#define __LWMI_ATTR_RO(_func, _name)                                  \
  1084		{                                                             \
  1085			.attr = { .name = __stringify(_name), .mode = 0444 }, \
  1086			.show = _func##_##_name##_show,                       \
  1087		}
  1088	
  1089	#define __LWMI_ATTR_RO_AS(_name, _show)                               \
  1090		{                                                             \
  1091			.attr = { .name = __stringify(_name), .mode = 0444 }, \
  1092			.show = _show,                                        \
  1093		}
  1094	
  1095	#define __LWMI_ATTR_RW(_func, _name) \
  1096		__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
  1097	
  1098	/* Shows a formatted static variable */
  1099	#define __LWMI_ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                     \
  1100		static ssize_t _attrname##_##_prop##_show(                             \
  1101			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1102		{                                                                      \
  1103			return sysfs_emit(buf, _fmt, _val);                            \
  1104		}                                                                      \
  1105		static struct kobj_attribute attr_##_attrname##_##_prop =              \
  1106			__LWMI_ATTR_RO(_attrname, _prop)
  1107	
  1108	/* Attribute current value read/write */
  1109	#define __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname)                          \
  1110		static ssize_t _attrname##_current_value_store(                        \
  1111			struct kobject *kobj, struct kobj_attribute *kattr,            \
  1112			const char *buf, size_t count)                                 \
  1113		{                                                                      \
  1114			return attr_current_value_store(kobj, kattr, buf, count,       \
  1115							&_attrname);                   \
  1116		}                                                                      \
  1117		static ssize_t _attrname##_current_value_show(                         \
  1118			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1119		{                                                                      \
  1120			return attr_current_value_show(kobj, kattr, buf, &_attrname);  \
  1121		}                                                                      \
  1122		static struct kobj_attribute attr_##_attrname##_current_value =        \
  1123			__LWMI_ATTR_RW(_attrname, current_value)
  1124	
  1125	/* Attribute property read only */
  1126	#define __LWMI_TUNABLE_RO_CAP01(_prop, _attrname, _prop_type)                  \
  1127		static ssize_t _attrname##_##_prop##_show(                             \
  1128			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1129		{                                                                      \
  1130			return attr_capdata01_show(kobj, kattr, buf, &_attrname,       \
  1131						   _prop_type);                        \
  1132		}                                                                      \
  1133		static struct kobj_attribute attr_##_attrname##_##_prop =              \
  1134			__LWMI_ATTR_RO(_attrname, _prop)
  1135	
  1136	#define LWMI_ATTR_GROUP_TUNABLE_CAP01(_attrname, _fsname, _dispname)      \
  1137		__LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname);                    \
  1138		__LWMI_TUNABLE_RO_CAP01(default_value, _attrname, DEFAULT_VAL);   \
  1139		__LWMI_ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
  1140		__LWMI_TUNABLE_RO_CAP01(max_value, _attrname, MAX_VAL);           \
  1141		__LWMI_TUNABLE_RO_CAP01(min_value, _attrname, MIN_VAL);           \
  1142		__LWMI_TUNABLE_RO_CAP01(scalar_increment, _attrname, STEP_VAL);   \
  1143		static struct kobj_attribute attr_##_attrname##_type =            \
  1144			__LWMI_ATTR_RO_AS(type, int_type_show);                   \
  1145		static struct attribute *_attrname##_attrs[] = {                  \
  1146			&attr_##_attrname##_current_value.attr,                   \
  1147			&attr_##_attrname##_default_value.attr,                   \
  1148			&attr_##_attrname##_display_name.attr,                    \
  1149			&attr_##_attrname##_max_value.attr,                       \
  1150			&attr_##_attrname##_min_value.attr,                       \
  1151			&attr_##_attrname##_scalar_increment.attr,                \
  1152			&attr_##_attrname##_type.attr,                            \
  1153			NULL,                                                     \
  1154		};                                                                \
  1155		static const struct attribute_group _attrname##_attr_group = {    \
  1156			.name = _fsname, .attrs = _attrname##_attrs               \
  1157		}
  1158	
  1159	/* CPU tunable attributes */
  1160	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
  1161				      "Set the CPU sustained power limit");
  1162	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl_cl, "ppt_pl1_spl_cl",
  1163				      "Set the CPU cross loading sustained power limit");
  1164	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
  1165				      "Set the CPU slow package power tracking limit");
  1166	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt_cl, "ppt_pl2_sppt_cl",
  1167				      "Set the CPU cross loading slow package power tracking limit");
  1168	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
  1169				      "Set the CPU fast package power tracking limit");
  1170	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt_cl, "ppt_pl3_fppt_cl",
  1171				      "Set the CPU cross loading fast package power tracking limit");
  1172	LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_temp, "cpu_temp",
  1173				      "Set the CPU thermal load limit");
  1174	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_apu_spl, "ppt_pl1_apu_spl",
  1175				      "Set the APU sustained power limit");
  1176	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_cpu_cl, "ppt_cpu_cl",
  1177				      "Set the CPU cross loading power limit");
  1178	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_tau, "ppt_pl1_tau",
  1179				      "Set the CPU sustained power limit exceed duration");
  1180	LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_oc_stat, "cpu_oc_stat",
  1181				      "Set the CPU overclocking status");
  1182	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl, "ppt_pl4_ipl",
  1183				      "Set the CPU instantaneous power limit");
  1184	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl_cl, "ppt_pl4_ipl_cl",
  1185				      "Set the CPU cross loading instantaneous power limit");
  1186	
  1187	/* GPU tunable attributes */
  1188	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ppab, "gpu_nv_ppab",
  1189				      "Set the Nvidia GPU power performance aware boost limit");
  1190	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ctgp, "gpu_nv_ctgp",
  1191				      "Set the GPU configurable total graphics power");
  1192	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_temp, "gpu_temp",
  1193				      "Set the GPU thermal load limit");
  1194	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ac_offset, "gpu_nv_ac_offset",
  1195				      "Set the Nvidia GPU AC total processing power baseline offset");
  1196	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_oc_stat, "gpu_oc_stat",
  1197				      "Set the GPU overclocking status");
  1198	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_boost_clk, "gpu_boost_clk",
  1199				      "Set the dedicated GPU boost clock");
  1200	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_enable, "dgpu_enable",
  1201				      "Set the dedicated Nvidia GPU enabled status");
> 1202	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_mode, "gpu_mode",
  1203				      "Set the GPU mode by power limit");
  1204	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_didvid, "gpu_didvid",
  1205				      "Get the GPU device identifier and vendor identifier");
  1206	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_bpl, "gpu_nv_bpl",
  1207				      "Set the Nvidia GPU base power limit");
  1208	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_cpu_boost, "gpu_nv_cpu_boost",
  1209				      "Set the Nvidia GPU to CPU dynamic boost limit");
  1210	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU tunable attributes
  2026-02-13  8:02 ` [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU " Derek J. Clark
  2026-02-13 19:26   ` kernel test robot
@ 2026-02-13 20:28   ` kernel test robot
  1 sibling, 0 replies; 9+ messages in thread
From: kernel test robot @ 2026-02-13 20:28 UTC (permalink / raw)
  To: Derek J. Clark, Ilpo Järvinen, Hans de Goede
  Cc: oe-kbuild-all, Mark Pearson, Armin Wolf, Jonathan Corbet,
	Rong Zhang, Kurt Borja, Derek J . Clark, platform-driver-x86,
	linux-kernel

Hi Derek,

kernel test robot noticed the following build warnings:

[auto build test WARNING on next-20260212]
[cannot apply to linus/master v6.19 v6.19-rc8 v6.19-rc7 v6.19]
[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-Add-LWMI_ATTR_ID-Macro/20260213-161603
base:   next-20260212
patch link:    https://lore.kernel.org/r/20260213081243.794288-5-derekjohn.clark%40gmail.com
patch subject: [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU tunable attributes
config: i386-randconfig-003-20260213 (https://download.01.org/0day-ci/archive/20260214/202602140438.FqccdLwp-lkp@intel.com/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/20260214/202602140438.FqccdLwp-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602140438.FqccdLwp-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/lenovo/wmi-other.c:1202:31: warning: 'gpu_mode_attr_group' defined but not used [-Wunused-const-variable=]
    1202 | LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_mode, "gpu_mode",
         |                               ^~~~~~~~
   drivers/platform/x86/lenovo/wmi-other.c:1155:45: note: in definition of macro 'LWMI_ATTR_GROUP_TUNABLE_CAP01'
    1155 |         static const struct attribute_group _attrname##_attr_group = {    \
         |                                             ^~~~~~~~~


vim +/gpu_mode_attr_group +1202 drivers/platform/x86/lenovo/wmi-other.c

  1081	
  1082	/* Lenovo WMI Other Mode Attribute macros */
  1083	#define __LWMI_ATTR_RO(_func, _name)                                  \
  1084		{                                                             \
  1085			.attr = { .name = __stringify(_name), .mode = 0444 }, \
  1086			.show = _func##_##_name##_show,                       \
  1087		}
  1088	
  1089	#define __LWMI_ATTR_RO_AS(_name, _show)                               \
  1090		{                                                             \
  1091			.attr = { .name = __stringify(_name), .mode = 0444 }, \
  1092			.show = _show,                                        \
  1093		}
  1094	
  1095	#define __LWMI_ATTR_RW(_func, _name) \
  1096		__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
  1097	
  1098	/* Shows a formatted static variable */
  1099	#define __LWMI_ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                     \
  1100		static ssize_t _attrname##_##_prop##_show(                             \
  1101			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1102		{                                                                      \
  1103			return sysfs_emit(buf, _fmt, _val);                            \
  1104		}                                                                      \
  1105		static struct kobj_attribute attr_##_attrname##_##_prop =              \
  1106			__LWMI_ATTR_RO(_attrname, _prop)
  1107	
  1108	/* Attribute current value read/write */
  1109	#define __LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname)                          \
  1110		static ssize_t _attrname##_current_value_store(                        \
  1111			struct kobject *kobj, struct kobj_attribute *kattr,            \
  1112			const char *buf, size_t count)                                 \
  1113		{                                                                      \
  1114			return attr_current_value_store(kobj, kattr, buf, count,       \
  1115							&_attrname);                   \
  1116		}                                                                      \
  1117		static ssize_t _attrname##_current_value_show(                         \
  1118			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1119		{                                                                      \
  1120			return attr_current_value_show(kobj, kattr, buf, &_attrname);  \
  1121		}                                                                      \
  1122		static struct kobj_attribute attr_##_attrname##_current_value =        \
  1123			__LWMI_ATTR_RW(_attrname, current_value)
  1124	
  1125	/* Attribute property read only */
  1126	#define __LWMI_TUNABLE_RO_CAP01(_prop, _attrname, _prop_type)                  \
  1127		static ssize_t _attrname##_##_prop##_show(                             \
  1128			struct kobject *kobj, struct kobj_attribute *kattr, char *buf) \
  1129		{                                                                      \
  1130			return attr_capdata01_show(kobj, kattr, buf, &_attrname,       \
  1131						   _prop_type);                        \
  1132		}                                                                      \
  1133		static struct kobj_attribute attr_##_attrname##_##_prop =              \
  1134			__LWMI_ATTR_RO(_attrname, _prop)
  1135	
  1136	#define LWMI_ATTR_GROUP_TUNABLE_CAP01(_attrname, _fsname, _dispname)      \
  1137		__LWMI_TUNABLE_CURRENT_VALUE_CAP01(_attrname);                    \
  1138		__LWMI_TUNABLE_RO_CAP01(default_value, _attrname, DEFAULT_VAL);   \
  1139		__LWMI_ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \
  1140		__LWMI_TUNABLE_RO_CAP01(max_value, _attrname, MAX_VAL);           \
  1141		__LWMI_TUNABLE_RO_CAP01(min_value, _attrname, MIN_VAL);           \
  1142		__LWMI_TUNABLE_RO_CAP01(scalar_increment, _attrname, STEP_VAL);   \
  1143		static struct kobj_attribute attr_##_attrname##_type =            \
  1144			__LWMI_ATTR_RO_AS(type, int_type_show);                   \
  1145		static struct attribute *_attrname##_attrs[] = {                  \
  1146			&attr_##_attrname##_current_value.attr,                   \
  1147			&attr_##_attrname##_default_value.attr,                   \
  1148			&attr_##_attrname##_display_name.attr,                    \
  1149			&attr_##_attrname##_max_value.attr,                       \
  1150			&attr_##_attrname##_min_value.attr,                       \
  1151			&attr_##_attrname##_scalar_increment.attr,                \
  1152			&attr_##_attrname##_type.attr,                            \
  1153			NULL,                                                     \
  1154		};                                                                \
  1155		static const struct attribute_group _attrname##_attr_group = {    \
  1156			.name = _fsname, .attrs = _attrname##_attrs               \
  1157		}
  1158	
  1159	/* CPU tunable attributes */
  1160	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl, "ppt_pl1_spl",
  1161				      "Set the CPU sustained power limit");
  1162	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_spl_cl, "ppt_pl1_spl_cl",
  1163				      "Set the CPU cross loading sustained power limit");
  1164	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt, "ppt_pl2_sppt",
  1165				      "Set the CPU slow package power tracking limit");
  1166	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl2_sppt_cl, "ppt_pl2_sppt_cl",
  1167				      "Set the CPU cross loading slow package power tracking limit");
  1168	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt, "ppt_pl3_fppt",
  1169				      "Set the CPU fast package power tracking limit");
  1170	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl3_fppt_cl, "ppt_pl3_fppt_cl",
  1171				      "Set the CPU cross loading fast package power tracking limit");
  1172	LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_temp, "cpu_temp",
  1173				      "Set the CPU thermal load limit");
  1174	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_apu_spl, "ppt_pl1_apu_spl",
  1175				      "Set the APU sustained power limit");
  1176	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_cpu_cl, "ppt_cpu_cl",
  1177				      "Set the CPU cross loading power limit");
  1178	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl1_tau, "ppt_pl1_tau",
  1179				      "Set the CPU sustained power limit exceed duration");
  1180	LWMI_ATTR_GROUP_TUNABLE_CAP01(cpu_oc_stat, "cpu_oc_stat",
  1181				      "Set the CPU overclocking status");
  1182	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl, "ppt_pl4_ipl",
  1183				      "Set the CPU instantaneous power limit");
  1184	LWMI_ATTR_GROUP_TUNABLE_CAP01(ppt_pl4_ipl_cl, "ppt_pl4_ipl_cl",
  1185				      "Set the CPU cross loading instantaneous power limit");
  1186	
  1187	/* GPU tunable attributes */
  1188	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ppab, "gpu_nv_ppab",
  1189				      "Set the Nvidia GPU power performance aware boost limit");
  1190	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ctgp, "gpu_nv_ctgp",
  1191				      "Set the GPU configurable total graphics power");
  1192	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_temp, "gpu_temp",
  1193				      "Set the GPU thermal load limit");
  1194	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_ac_offset, "gpu_nv_ac_offset",
  1195				      "Set the Nvidia GPU AC total processing power baseline offset");
  1196	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_oc_stat, "gpu_oc_stat",
  1197				      "Set the GPU overclocking status");
  1198	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_boost_clk, "gpu_boost_clk",
  1199				      "Set the dedicated GPU boost clock");
  1200	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_enable, "dgpu_enable",
  1201				      "Set the dedicated Nvidia GPU enabled status");
> 1202	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_mode, "gpu_mode",
  1203				      "Set the GPU mode by power limit");
  1204	LWMI_ATTR_GROUP_TUNABLE_CAP01(dgpu_didvid, "gpu_didvid",
  1205				      "Get the GPU device identifier and vendor identifier");
  1206	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_bpl, "gpu_nv_bpl",
  1207				      "Set the Nvidia GPU base power limit");
  1208	LWMI_ATTR_GROUP_TUNABLE_CAP01(gpu_nv_cpu_boost, "gpu_nv_cpu_boost",
  1209				      "Set the Nvidia GPU to CPU dynamic boost limit");
  1210	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting.
  2026-02-13  8:02 ` [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting Derek J. Clark
@ 2026-02-13 22:59   ` kernel test robot
  0 siblings, 0 replies; 9+ messages in thread
From: kernel test robot @ 2026-02-13 22:59 UTC (permalink / raw)
  To: Derek J. Clark, Ilpo Järvinen, Hans de Goede
  Cc: oe-kbuild-all, Mark Pearson, Armin Wolf, Jonathan Corbet,
	Rong Zhang, Kurt Borja, Derek J . Clark, platform-driver-x86,
	linux-kernel

Hi Derek,

kernel test robot noticed the following build warnings:

[auto build test WARNING on next-20260212]
[cannot apply to linus/master v6.19 v6.19-rc8 v6.19-rc7 v6.19]
[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-Add-LWMI_ATTR_ID-Macro/20260213-161603
base:   next-20260212
patch link:    https://lore.kernel.org/r/20260213081243.794288-6-derekjohn.clark%40gmail.com
patch subject: [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting.
config: i386-randconfig-003-20260213 (https://download.01.org/0day-ci/archive/20260214/202602140643.fEZnDqbv-lkp@intel.com/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/20260214/202602140643.fEZnDqbv-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602140643.fEZnDqbv-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> Warning: drivers/platform/x86/lenovo/wmi-other.c:600 function parameter 'data' not described in 'lwmi_psy_ext_get_prop'
>> Warning: drivers/platform/x86/lenovo/wmi-other.c:600 expecting prototype for lwmi_psy_prop_is_writeable(). Prototype was for lwmi_psy_ext_get_prop() instead
>> Warning: drivers/platform/x86/lenovo/wmi-other.c:641 expecting prototype for lwmi_psy_prop_is_writeable(). Prototype was for lwmi_psy_ext_set_prop() instead
>> Warning: drivers/platform/x86/lenovo/wmi-other.c:745 function parameter 'handle' not described in 'lwmi_acpi_match'
>> Warning: drivers/platform/x86/lenovo/wmi-other.c:745 function parameter 'handle' not described in 'lwmi_acpi_match'

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-02-13 22:59 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-13  8:02 [PATCH 0/5] platform-x86: lenovo-wmi: Add fixes and enhancement Derek J. Clark
2026-02-13  8:02 ` [PATCH 1/5] platform/x86: lenovo-wmi-other: Add LWMI_ATTR_ID Macro Derek J. Clark
2026-02-13  8:02 ` [PATCH 2/5] platform/x86: lenovo-wmi-other: Limit adding attributes to supported devices Derek J. Clark
2026-02-13  8:02 ` [PATCH 3/5] platform/x86: lenovo-wmi-other: Add missing CPU tunable attributes Derek J. Clark
2026-02-13  8:02 ` [PATCH 4/5] platform/x86: lenovo-wmi-other: Add GPU " Derek J. Clark
2026-02-13 19:26   ` kernel test robot
2026-02-13 20:28   ` kernel test robot
2026-02-13  8:02 ` [PATCH 5/5] platform/x86: lenovo-wmi-other: Add WMI battery charge limiting Derek J. Clark
2026-02-13 22:59   ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox