[RESEND PATCH 1/5] platform/x86: bitland-mifs-wmi: validate WMAA status, never abort suspend
孙 誉铭 <[email protected]> Tue, 28 Jul 2026 18:09:55 +0000
| Newsgroups | org.kernel.vger.platform-driver-x86,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The WMAA firmware method signals "unknown/unsupported function" with the status word 0xe000 in the reply. The driver never checked it, so calls to functions a given firmware revision does not implement silently returned zero-filled data instead of failing. Worse, the platform_profile suspend hook propagated such errors: on firmware whose perf-mode query returns values laptop_profile_get() cannot map (e.g. MIFS v2 firmware reporting raw QFAN codes, seen on Xiaomi Book Pro 14 2026 and REDMI Book Pro 14 2025), every suspend attempt died with: dpm_run_callback(): bitland_mifs_wmi_suspend returns -22 PM: Some devices failed to suspend, or early wake event detected Return -EOPNOTSUPP when the firmware reports the error status word, and make the suspend/resume hooks fault-tolerant: skip saving and restoring the profile when the query fails instead of aborting the whole system sleep. Status word semantics verified against the laptop's SSDT WMAA method (SGER=0x8000 on success, 0xe000 in the Default branch). Signed-off-by: Yuming Sun <[email protected]> --- drivers/platform/x86/bitland-mifs-wmi.c | 31 +++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/bitland-mifs-wmi.c b/drivers/platform/x86/bitland-mifs-wmi.c index 3a373184..12426d11 100644 --- a/drivers/platform/x86/bitland-mifs-wmi.c +++ b/drivers/platform/x86/bitland-mifs-wmi.c @@ -129,6 +129,18 @@ struct bitland_mifs_output { u8 data[28]; } __packed; +/* + * The status word of a WMAA reply is formed by the first two bytes + * (reserved1 | operation << 8). MIFS firmware signals "unknown or + * unsupported function" with 0xe000 and success with 0x8000. + */ +#define MIFS_STATUS_ERROR 0xe000 + +static u16 mifs_status(const struct bitland_mifs_output *out) +{ + return out->reserved1 | (out->operation << 8); +} + struct bitland_mifs_event { u8 event_type; u8 event_id; @@ -159,6 +171,7 @@ struct bitland_mifs_wmi_data { struct device *hwmon_dev; struct device *pp_dev; enum platform_profile_option saved_profile; + bool profile_valid; }; static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data, @@ -181,6 +194,9 @@ static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data, memcpy(output, out_buf.data, sizeof(*output)); kfree(out_buf.data); + if (mifs_status(output) == MIFS_STATUS_ERROR) + return -EOPNOTSUPP; + return 0; } @@ -298,17 +314,21 @@ static int bitland_mifs_wmi_suspend(struct device *dev) { struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev); enum platform_profile_option profile; - int ret; /* Skip event device */ if (!data->pp_dev) return 0; - ret = laptop_profile_get(data->pp_dev, &profile); - if (ret == 0) + /* + * Never abort suspend: some firmware revisions answer the perf-mode + * query with values this driver cannot map, or fail the call + * entirely while the system is going down. + */ + data->profile_valid = laptop_profile_get(data->pp_dev, &profile) == 0; + if (data->profile_valid) data->saved_profile = profile; - return ret; + return 0; } static int bitland_mifs_wmi_resume(struct device *dev) @@ -319,6 +339,9 @@ static int bitland_mifs_wmi_resume(struct device *dev) if (!data->pp_dev) return 0; + if (!data->profile_valid) + return 0; + dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile); return laptop_profile_set(dev, data->saved_profile); } -- 2.55.0