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: alienware-wmi-wmax: Improve platform profile probe

Get and store the AWCC system description in alienware_awcc_setup()
instead of awcc_platform_profile_probe() and get the correct offset by
iterating through each member of the system_description.

Then add a debug message for unmatched profiles and replace set_bit()
with it's non-atomic version __set_bit() because the choices bitmap only
belongs to this thread.

In the process also check for a malformed system description by defining
an arbitrary limit of resource count.

Reviewed-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Kurt Borja <kuurtb@gmail.com>
Link: https://lore.kernel.org/r/20250329-hwm-v7-5-a14ea39d8a94@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

Kurt Borja and committed by
Ilpo Järvinen
32b6372d 77bb2ec5

+47 -16
+47 -16
drivers/platform/x86/dell/alienware-wmi-wmax.c
··· 8 8 9 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 10 11 + #include <linux/array_size.h> 11 12 #include <linux/bitfield.h> 12 13 #include <linux/bits.h> 13 14 #include <linux/dmi.h> ··· 39 38 #define AWCC_THERMAL_MODE_MASK GENMASK(3, 0) 40 39 #define AWCC_THERMAL_TABLE_MASK GENMASK(7, 4) 41 40 #define AWCC_RESOURCE_ID_MASK GENMASK(7, 0) 41 + 42 + /* Arbitrary limit based on supported models */ 43 + #define AWCC_MAX_RES_COUNT 16 42 44 43 45 static bool force_platform_profile; 44 46 module_param_unsafe(force_platform_profile, bool, 0); ··· 217 213 218 214 struct awcc_priv { 219 215 struct wmi_device *wdev; 216 + union { 217 + u32 system_description; 218 + struct { 219 + u8 fan_count; 220 + u8 temp_count; 221 + u8 unknown_count; 222 + u8 profile_count; 223 + }; 224 + u8 res_count[4]; 225 + }; 226 + 220 227 struct device *ppdev; 221 228 u8 supported_profiles[PLATFORM_PROFILE_LAST]; 222 229 }; ··· 648 633 enum platform_profile_option profile; 649 634 struct awcc_priv *priv = drvdata; 650 635 enum awcc_thermal_profile mode; 651 - u8 sys_desc[4]; 652 - u32 first_mode; 636 + u8 id, offset = 0; 653 637 int ret; 654 - u8 id; 655 638 656 - ret = awcc_thermal_information(priv->wdev, AWCC_OP_GET_SYSTEM_DESCRIPTION, 657 - 0, (u32 *) &sys_desc); 658 - if (ret < 0) 659 - return ret; 639 + /* 640 + * Thermal profile IDs are listed last at offset 641 + * fan_count + temp_count + unknown_count 642 + */ 643 + for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count) - 1; i++) 644 + offset += priv->res_count[i]; 660 645 661 - first_mode = sys_desc[0] + sys_desc[1]; 662 - 663 - for (u32 i = 0; i < sys_desc[3]; i++) { 664 - ret = awcc_op_get_resource_id(priv->wdev, i + first_mode, &id); 665 - 646 + for (unsigned int i = 0; i < priv->profile_count; i++) { 647 + ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id); 666 648 if (ret == -EIO) 667 649 return ret; 668 - 650 + /* 651 + * Some devices report an incorrect number of thermal profiles 652 + * so the resource ID list may end prematurely 653 + */ 669 654 if (ret == -EBADRQC) 670 655 break; 671 656 672 - if (!is_awcc_thermal_profile_id(id)) 657 + if (!is_awcc_thermal_profile_id(id)) { 658 + dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id); 673 659 continue; 660 + } 674 661 675 662 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id); 676 663 profile = awcc_mode_to_platform_profile[mode]; 677 664 priv->supported_profiles[profile] = id; 678 665 679 - set_bit(profile, choices); 666 + __set_bit(profile, choices); 680 667 } 681 668 682 669 if (bitmap_empty(choices, PLATFORM_PROFILE_LAST)) ··· 688 671 priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] = 689 672 AWCC_THERMAL_MODE_GMODE; 690 673 691 - set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 674 + __set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); 692 675 } 693 676 694 677 return 0; ··· 718 701 priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); 719 702 if (!priv) 720 703 return -ENOMEM; 704 + 705 + ret = awcc_thermal_information(wdev, AWCC_OP_GET_SYSTEM_DESCRIPTION, 706 + 0, &priv->system_description); 707 + if (ret < 0) 708 + return ret; 709 + 710 + /* Sanity check */ 711 + for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count); i++) { 712 + if (priv->res_count[i] > AWCC_MAX_RES_COUNT) { 713 + dev_err(&wdev->dev, "Malformed system description: 0x%08x\n", 714 + priv->system_description); 715 + return -ENXIO; 716 + } 717 + } 721 718 722 719 priv->wdev = wdev; 723 720 dev_set_drvdata(&wdev->dev, priv);