Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Krishna Chomal and committed by
Ilpo Järvinen
9d317a54 92c36b63

+33 -8
+33 -8
drivers/platform/x86/hp/hp-wmi.c
··· 469 469 }; 470 470 471 471 struct victus_s_fan_table_header { 472 + u8 num_fans; 472 473 u8 unknown; 473 - u8 num_entries; 474 474 } __packed; 475 475 476 476 struct victus_s_fan_table_entry { 477 477 u8 cpu_rpm; 478 478 u8 gpu_rpm; 479 - u8 unknown; 479 + u8 noise_db; 480 480 } __packed; 481 481 482 482 struct victus_s_fan_table { ··· 2563 2563 u8 fan_data[128] = { 0 }; 2564 2564 struct victus_s_fan_table *fan_table; 2565 2565 u8 min_rpm, max_rpm; 2566 - int gpu_delta, ret; 2566 + u8 cpu_rpm, gpu_rpm, noise_db; 2567 + int gpu_delta, i, num_entries, ret; 2568 + size_t header_size, entry_size; 2567 2569 2568 2570 /* Default behaviour on hwmon init is automatic mode */ 2569 2571 priv->mode = PWM_MODE_AUTO; ··· 2580 2578 return ret; 2581 2579 2582 2580 fan_table = (struct victus_s_fan_table *)fan_data; 2583 - if (fan_table->header.num_entries == 0 || 2584 - sizeof(struct victus_s_fan_table_header) + 2585 - sizeof(struct victus_s_fan_table_entry) * fan_table->header.num_entries > sizeof(fan_data)) 2581 + if (fan_table->header.num_fans == 0) 2586 2582 return -EINVAL; 2587 2583 2588 - min_rpm = fan_table->entries[0].cpu_rpm; 2589 - max_rpm = fan_table->entries[fan_table->header.num_entries - 1].cpu_rpm; 2584 + header_size = sizeof(struct victus_s_fan_table_header); 2585 + entry_size = sizeof(struct victus_s_fan_table_entry); 2586 + num_entries = (sizeof(fan_data) - header_size) / entry_size; 2587 + min_rpm = U8_MAX; 2588 + max_rpm = 0; 2589 + 2590 + for (i = 0 ; i < num_entries ; i++) { 2591 + cpu_rpm = fan_table->entries[i].cpu_rpm; 2592 + gpu_rpm = fan_table->entries[i].gpu_rpm; 2593 + noise_db = fan_table->entries[i].noise_db; 2594 + 2595 + /* 2596 + * On some devices, the fan table is truncated with an all-zero row, 2597 + * hence we stop parsing here. 2598 + */ 2599 + if (cpu_rpm == 0 && gpu_rpm == 0 && noise_db == 0) 2600 + break; 2601 + 2602 + if (cpu_rpm < min_rpm) 2603 + min_rpm = cpu_rpm; 2604 + if (cpu_rpm > max_rpm) 2605 + max_rpm = cpu_rpm; 2606 + } 2607 + 2608 + if (min_rpm == U8_MAX || max_rpm == 0) 2609 + return -EINVAL; 2610 + 2590 2611 gpu_delta = fan_table->entries[0].gpu_rpm - fan_table->entries[0].cpu_rpm; 2591 2612 priv->min_rpm = min_rpm; 2592 2613 priv->max_rpm = max_rpm;