[PATCH 7/9] platform/x86: lenovo-wmi-capdata: Detect stubbed capdata device

From: Rong Zhang

Date: Sun Sep 13 2026 - 16:53:15 EST


Some devices may stub the capdata device's WMI query method because it
doesn't support the relevant interfaces at all. For example, most
ThinkBook devices doesn't support GameZone or Other Mode thermal tuning,
so capdata 01 is useless and stubbed.

Keeping the capability data list with empty data is meaningless and
causes lenovo-wmi-other to call lwmi_cd*_get_data() to retrieve
nonexistent capdata in vain.

Therefore, poison the device and release (or skip allocating) needless
resources, e.g., the capability data list and the debugfs directory.

Signed-off-by: Rong Zhang <i@xxxxxxxx>
---
drivers/platform/x86/lenovo/wmi-capdata.c | 33 +++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c
index d4d5e8c97ddb..805e36ef7f31 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.c
+++ b/drivers/platform/x86/lenovo/wmi-capdata.c
@@ -668,6 +668,7 @@ static int lwmi_cd_poison(struct lwmi_cd_priv *priv, int err)
*/
static int __lwmi_cd_cache(struct lwmi_cd_priv *priv)
{
+ bool got_data = false;
size_t size;
int idx;
void *p;
@@ -702,8 +703,31 @@ static int __lwmi_cd_cache(struct lwmi_cd_priv *priv)
struct capdata00 *capdata __free(kfree) = wbuf.data;

memcpy(p, capdata, size);
+
+ /*
+ * A valid attribute always has a non-zero id. IOW, a zero id
+ * implies a stubbed item (or the query method being stubbed).
+ *
+ * The stubbed item is still copied to the cache slot anyway, in
+ * case the firmware dynamically stubs the capdata item after
+ * switching Game Zone mode. In this manner, the previously
+ * exposed capdata can be void.
+ */
+ if (capdata->id)
+ got_data = true;
}

+ /*
+ * Some devices may stub the query method because it doesn't support the
+ * relevant interfaces at all. For example, most ThinkBook devices
+ * doesn't support Game Zone or Other Mode thermal tuning, so capdata 01
+ * is useless and stubbed.
+ *
+ * Poison the device and release needless resources.
+ */
+ if (!got_data)
+ return lwmi_cd_poison(priv, -ENODATA);
+
return 0;
}

@@ -743,6 +767,7 @@ static int lwmi_cd_cache(struct lwmi_cd_priv *priv)
static int lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv *priv)
{
struct wmi_buffer wbuf;
+ bool got_data = false;
struct cd_list *list;
int ret, idx;
u32 count;
@@ -785,14 +810,22 @@ static int lwmi_cd_fan_list_alloc_cache(struct lwmi_cd_priv *priv)
priv->list = list;

for (idx = 0; idx < count; idx++) {
+ if (!block->data[idx]) /* Ignore stub. */
+ continue;
+
/* Do not calculate array index using count, as it may be truncated. */
list->cd_fan[idx] = (struct capdata_fan) {
.id = block->data[idx],
.max_rpm = block->data[idx + block->nr],
.min_rpm = block->data[idx + (2 * block->nr)],
};
+
+ got_data = true;
}

+ if (!got_data)
+ return lwmi_cd_poison(priv, -ENODATA);
+
return 0;
}


--
2.55.0