diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c index 7310b72e8c2f..b86bc7a57a04 100644 --- a/drivers/platform/x86/lenovo/wmi-capdata.c +++ b/drivers/platform/x86/lenovo/wmi-capdata.c @@ -691,6 +691,7 @@ static int lwmi_cd_stub(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; @@ -725,8 +726,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. + * + * Stub the device and release needless resources. + */ + if (!got_data) + return lwmi_cd_stub(priv, -ENODATA); + return 0; } @@ -772,6 +796,7 @@ struct lwmi_cd_fan_block { 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; @@ -808,13 +833,21 @@ 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; + list->cd_fan[idx] = (struct capdata_fan) { .id = block->data[idx], .max_rpm = block->data[idx + count], .min_rpm = block->data[idx + (2 * count)], }; + + got_data = true; } + if (!got_data) + return lwmi_cd_stub(priv, -ENODATA); + return 0; }