diff options
| author | Krishna Chomal <krishna.chomal108@gmail.com> | 2026-04-11 00:40:36 +0530 |
|---|---|---|
| committer | Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> | 2026-04-14 19:00:11 +0300 |
| commit | 9d317a54e46d3b6420567dc5b63e9d7ff5c064a3 (patch) | |
| tree | 53e9913226144713767d71b96df094e41b6cf3a5 /drivers/platform | |
| parent | 92c36b634b4586e02409488fa02a4908ee4ebea7 (diff) | |
| download | linux-next-9d317a54e46d3b6420567dc5b63e9d7ff5c064a3.tar.gz linux-next-9d317a54e46d3b6420567dc5b63e9d7ff5c064a3.zip | |
platform/x86: hp-wmi: fix fan table parsing
For Victus S devices, the BIOS fan table header was being incorrectly
parsed as:
struct {
u8 unknown;
u8 num_entries;
}
The first field should be num_fans and the second should be unknown. It
is pure coincidence that interpreting an "unknown" field as "num_entries"
worked on multiple device, however for board 8D87 (in an upcoming patch),
this assumption fails, and the hp-wmi driver fails to load.
We fix this by correcting the header definition and compensating for
num_entries by parsing each entry of the fan table until an all-NULL row
is obtained, mirroring the behavior of OMEN Gaming Hub on Windows.
Fixes: 46be1453e6e6 ("platform/x86: hp-wmi: add manual fan control for Victus S models")
Signed-off-by: Krishna Chomal <krishna.chomal108@gmail.com>
Link: https://patch.msgid.link/20260410191039.125659-2-krishna.chomal108@gmail.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/x86/hp/hp-wmi.c | 41 |
1 files changed, 33 insertions, 8 deletions
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 77913373ed08..205a7bf4cbf7 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -469,14 +469,14 @@ struct hp_wmi_hwmon_priv { }; struct victus_s_fan_table_header { + u8 num_fans; u8 unknown; - u8 num_entries; } __packed; struct victus_s_fan_table_entry { u8 cpu_rpm; u8 gpu_rpm; - u8 unknown; + u8 noise_db; } __packed; struct victus_s_fan_table { @@ -2563,7 +2563,9 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) u8 fan_data[128] = { 0 }; struct victus_s_fan_table *fan_table; u8 min_rpm, max_rpm; - int gpu_delta, ret; + u8 cpu_rpm, gpu_rpm, noise_db; + int gpu_delta, i, num_entries, ret; + size_t header_size, entry_size; /* Default behaviour on hwmon init is automatic mode */ priv->mode = PWM_MODE_AUTO; @@ -2578,13 +2580,36 @@ static int hp_wmi_setup_fan_settings(struct hp_wmi_hwmon_priv *priv) return ret; fan_table = (struct victus_s_fan_table *)fan_data; - if (fan_table->header.num_entries == 0 || - sizeof(struct victus_s_fan_table_header) + - sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data)) + if (fan_table->header.num_fans == 0) + return -EINVAL; + + header_size = sizeof(struct victus_s_fan_table_header); + entry_size = sizeof(struct victus_s_fan_table_entry); + num_entries = (sizeof(fan_data) - header_size) / entry_size; + min_rpm = U8_MAX; + max_rpm = 0; + + for (i = 0 ; i < num_entries ; i++) { + cpu_rpm = fan_table->entries[i].cpu_rpm; + gpu_rpm = fan_table->entries[i].gpu_rpm; + noise_db = fan_table->entries[i].noise_db; + + /* + * On some devices, the fan table is truncated with an all-zero row, + * hence we stop parsing here. + */ + if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0) + break; + + if (cpu_rpm < min_rpm) + min_rpm = cpu_rpm; + if (cpu_rpm > max_rpm) + max_rpm = cpu_rpm; + } + + if (min_rpm == U8_MAX || max_rpm == 0) return -EINVAL; - min_rpm = fan_table->entries[0].cpu_rpm; - max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm; gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm; priv->min_rpm = min_rpm; priv->max_rpm = max_rpm; |
