* [RFC PATCH 0/3] platform/x86: acer-wmi: Add fan control support
@ 2025-02-14 22:13 Armin Wolf
2025-02-14 22:13 ` [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior Armin Wolf
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Armin Wolf @ 2025-02-14 22:13 UTC (permalink / raw)
To: jlee, basak.sb2006, rayanmargham4
Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel
This experimental patch series aims to add fan control support to the
acer-wmi driver. The patches are compile-tested only and need to be
tested on real hardware to verify that they actually work.
I CCed two users who requested support for this feature. I would be
very happy if both of you could test those patches and report back.
I am ready to help you both with compiling a custom linux kernel for
testing this series.
Armin Wolf (3):
platform/x86: acer-wmi: Fix setting of fan behavior
platform/x86: acer-wmi: Add fan control support
platform/x86: acer-wmi: Enable fan control for PH16-72 and PT14-51
drivers/platform/x86/acer-wmi.c | 299 +++++++++++++++++++++++++++++---
1 file changed, 274 insertions(+), 25 deletions(-)
--
2.39.5
^ permalink raw reply [flat|nested] 10+ messages in thread* [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior 2025-02-14 22:13 [RFC PATCH 0/3] platform/x86: acer-wmi: Add fan control support Armin Wolf @ 2025-02-14 22:13 ` Armin Wolf 2025-02-15 1:30 ` Kurt Borja 2025-02-14 22:13 ` [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 3/3] platform/x86: acer-wmi: Enable fan control for PH16-72 and PT14-51 Armin Wolf 2 siblings, 1 reply; 10+ messages in thread From: Armin Wolf @ 2025-02-14 22:13 UTC (permalink / raw) To: jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel After studying the linuwu_sense driver (https://github.com/0x7375646F/Linuwu-Sense) i was able to understand the meaning of the SetGamingFanBehavior() WMI method: - the first 16-bit are a bitmap of all fans affected by a fan behavior change request. - the next 8 bits contain four fan mode fields (2-bit), each being associated with a bit inside the fan bitmap. There are three fan modes: auto, turbo and custom. Use this newfound knowledge to fix the turbo fan handling by setting the correct bits before calling SetGamingFanBehavior(). Also check the result of the WMI method call and return an error should the ACPI firmware signal failure. Signed-off-by: Armin Wolf <W_Armin@gmx.de> --- drivers/platform/x86/acer-wmi.c | 75 +++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 69336bd778ee..f20a882e3650 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -68,10 +68,19 @@ MODULE_LICENSE("GPL"); #define ACER_WMID_SET_GAMING_LED_METHODID 2 #define ACER_WMID_GET_GAMING_LED_METHODID 4 #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) +#define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) + +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) + +#define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) +#define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) + #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) @@ -121,6 +130,12 @@ enum acer_wmi_predator_v4_sensor_id { ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, }; +enum acer_wmi_gaming_fan_mode { + ACER_WMID_FAN_MODE_AUTO = 0x01, + ACER_WMID_FAN_MODE_TURBO = 0x02, + ACER_WMID_FAN_MODE_CUSTOM = 0x03, +}; + enum acer_wmi_predator_v4_oc { ACER_WMID_OC_NORMAL = 0x0000, ACER_WMID_OC_TURBO = 0x0002, @@ -1565,9 +1580,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) case ACER_CAP_TURBO_LED: method_id = ACER_WMID_SET_GAMING_LED_METHODID; break; - case ACER_CAP_TURBO_FAN: - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; - break; default: return AE_BAD_PARAMETER; } @@ -1618,25 +1630,42 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) return 0; } +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) +{ + acpi_status status; + u64 input = 0; + u64 result; + + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK, mode_bitmap); + + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + /* TODO: Proper error handling */ + pr_notice("Fan behavior return status: %llu\n", result); + + return 0; +} + static void WMID_gaming_set_fan_mode(u8 fan_mode) { - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; - int i; - - if (quirks->cpu_fans > 0) - gpu_fan_config2 |= 1; - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) - gpu_fan_config2 |= 1 << (i + 1); - for (i = 0; i < quirks->gpu_fans; ++i) - gpu_fan_config2 |= 1 << (i + 3); - if (quirks->cpu_fans > 0) - gpu_fan_config1 |= fan_mode; - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) - gpu_fan_config1 |= fan_mode << (2 * i + 2); - for (i = 0; i < quirks->gpu_fans; ++i) - gpu_fan_config1 |= fan_mode << (2 * i + 6); - WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN); + u16 mode_bitmap = 0; + u16 fan_bitmap = 0; + + if (quirks->cpu_fans > 0) { + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_CPU; + mode_bitmap |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, fan_mode); + } + + if (quirks->gpu_fans > 0) { + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_GPU; + mode_bitmap |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, fan_mode); + } + + WMID_gaming_set_fan_behavior(fan_bitmap, mode_bitmap); } static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value) @@ -1923,7 +1952,7 @@ static int acer_toggle_turbo(void) WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED); /* Set FAN mode to auto */ - WMID_gaming_set_fan_mode(0x1); + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_AUTO); /* Set OC to normal */ if (has_cap(ACER_CAP_TURBO_OC)) { @@ -1937,7 +1966,7 @@ static int acer_toggle_turbo(void) WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED); /* Set FAN mode to turbo */ - WMID_gaming_set_fan_mode(0x2); + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_TURBO); /* Set OC to turbo mode */ if (has_cap(ACER_CAP_TURBO_OC)) { -- 2.39.5 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior 2025-02-14 22:13 ` [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior Armin Wolf @ 2025-02-15 1:30 ` Kurt Borja 2025-02-15 17:40 ` Armin Wolf 0 siblings, 1 reply; 10+ messages in thread From: Kurt Borja @ 2025-02-15 1:30 UTC (permalink / raw) To: Armin Wolf, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Hi Armin, On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: > After studying the linuwu_sense driver > (https://github.com/0x7375646F/Linuwu-Sense) i was able to understand > the meaning of the SetGamingFanBehavior() WMI method: > > - the first 16-bit are a bitmap of all fans affected by a fan behavior > change request. > > - the next 8 bits contain four fan mode fields (2-bit), each being > associated with a bit inside the fan bitmap. > > There are three fan modes: auto, turbo and custom. > > Use this newfound knowledge to fix the turbo fan handling by setting > the correct bits before calling SetGamingFanBehavior(). Also check > the result of the WMI method call and return an error should the ACPI > firmware signal failure. > > Signed-off-by: Armin Wolf <W_Armin@gmx.de> > --- > drivers/platform/x86/acer-wmi.c | 75 +++++++++++++++++++++++---------- > 1 file changed, 52 insertions(+), 23 deletions(-) > > -- > 2.39.5 > > diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c > index 69336bd778ee..f20a882e3650 100644 > --- a/drivers/platform/x86/acer-wmi.c > +++ b/drivers/platform/x86/acer-wmi.c > @@ -68,10 +68,19 @@ MODULE_LICENSE("GPL"); > #define ACER_WMID_SET_GAMING_LED_METHODID 2 > #define ACER_WMID_GET_GAMING_LED_METHODID 4 > #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 > -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 > +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 > #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 > #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 > > +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) > +#define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) > + > +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) > +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) > + > +#define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) > +#define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) > + > #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) > #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) > #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) > @@ -121,6 +130,12 @@ enum acer_wmi_predator_v4_sensor_id { > ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, > }; > > +enum acer_wmi_gaming_fan_mode { > + ACER_WMID_FAN_MODE_AUTO = 0x01, > + ACER_WMID_FAN_MODE_TURBO = 0x02, > + ACER_WMID_FAN_MODE_CUSTOM = 0x03, > +}; > + > enum acer_wmi_predator_v4_oc { > ACER_WMID_OC_NORMAL = 0x0000, > ACER_WMID_OC_TURBO = 0x0002, > @@ -1565,9 +1580,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) > case ACER_CAP_TURBO_LED: > method_id = ACER_WMID_SET_GAMING_LED_METHODID; > break; > - case ACER_CAP_TURBO_FAN: > - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; > - break; > default: > return AE_BAD_PARAMETER; > } > @@ -1618,25 +1630,42 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) > return 0; > } > > +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) > +{ > + acpi_status status; > + u64 input = 0; > + u64 result; > + > + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); > + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK, mode_bitmap); > + > + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, > + &result); > + if (ACPI_FAILURE(status)) > + return -EIO; > + > + /* TODO: Proper error handling */ > + pr_notice("Fan behavior return status: %llu\n", result); > + > + return 0; > +} > + > static void WMID_gaming_set_fan_mode(u8 fan_mode) > { > - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ > - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; > - int i; > - > - if (quirks->cpu_fans > 0) > - gpu_fan_config2 |= 1; > - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) > - gpu_fan_config2 |= 1 << (i + 1); This was not replicated bellow. Just to be sure, are there no fans at BIT(1) and BIT(2)? > - for (i = 0; i < quirks->gpu_fans; ++i) > - gpu_fan_config2 |= 1 << (i + 3); > - if (quirks->cpu_fans > 0) > - gpu_fan_config1 |= fan_mode; > - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) > - gpu_fan_config1 |= fan_mode << (2 * i + 2); Same as above. -- ~ Kurt > - for (i = 0; i < quirks->gpu_fans; ++i) > - gpu_fan_config1 |= fan_mode << (2 * i + 6); > - WMID_gaming_set_u64(gpu_fan_config2 | gpu_fan_config1 << 16, ACER_CAP_TURBO_FAN); > + u16 mode_bitmap = 0; > + u16 fan_bitmap = 0; > + > + if (quirks->cpu_fans > 0) { > + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_CPU; > + mode_bitmap |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, fan_mode); > + } > + > + if (quirks->gpu_fans > 0) { > + fan_bitmap |= ACER_GAMING_FAN_BEHAVIOR_GPU; > + mode_bitmap |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, fan_mode); > + } > + > + WMID_gaming_set_fan_behavior(fan_bitmap, mode_bitmap); > } > > static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value) > @@ -1923,7 +1952,7 @@ static int acer_toggle_turbo(void) > WMID_gaming_set_u64(0x1, ACER_CAP_TURBO_LED); > > /* Set FAN mode to auto */ > - WMID_gaming_set_fan_mode(0x1); > + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_AUTO); > > /* Set OC to normal */ > if (has_cap(ACER_CAP_TURBO_OC)) { > @@ -1937,7 +1966,7 @@ static int acer_toggle_turbo(void) > WMID_gaming_set_u64(0x10001, ACER_CAP_TURBO_LED); > > /* Set FAN mode to turbo */ > - WMID_gaming_set_fan_mode(0x2); > + WMID_gaming_set_fan_mode(ACER_WMID_FAN_MODE_TURBO); > > /* Set OC to turbo mode */ > if (has_cap(ACER_CAP_TURBO_OC)) { ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior 2025-02-15 1:30 ` Kurt Borja @ 2025-02-15 17:40 ` Armin Wolf 2025-02-15 18:07 ` Kurt Borja 0 siblings, 1 reply; 10+ messages in thread From: Armin Wolf @ 2025-02-15 17:40 UTC (permalink / raw) To: Kurt Borja, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Am 15.02.25 um 02:30 schrieb Kurt Borja: > Hi Armin, > > On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: >> After studying the linuwu_sense driver >> (https://github.com/0x7375646F/Linuwu-Sense) i was able to understand >> the meaning of the SetGamingFanBehavior() WMI method: >> >> - the first 16-bit are a bitmap of all fans affected by a fan behavior >> change request. >> >> - the next 8 bits contain four fan mode fields (2-bit), each being >> associated with a bit inside the fan bitmap. >> >> There are three fan modes: auto, turbo and custom. >> >> Use this newfound knowledge to fix the turbo fan handling by setting >> the correct bits before calling SetGamingFanBehavior(). Also check >> the result of the WMI method call and return an error should the ACPI >> firmware signal failure. >> >> Signed-off-by: Armin Wolf <W_Armin@gmx.de> >> --- >> drivers/platform/x86/acer-wmi.c | 75 +++++++++++++++++++++++---------- >> 1 file changed, 52 insertions(+), 23 deletions(-) >> >> -- >> 2.39.5 >> >> diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c >> index 69336bd778ee..f20a882e3650 100644 >> --- a/drivers/platform/x86/acer-wmi.c >> +++ b/drivers/platform/x86/acer-wmi.c >> @@ -68,10 +68,19 @@ MODULE_LICENSE("GPL"); >> #define ACER_WMID_SET_GAMING_LED_METHODID 2 >> #define ACER_WMID_GET_GAMING_LED_METHODID 4 >> #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 >> -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 >> +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 >> #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 >> #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 >> >> +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) >> +#define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) >> + >> +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) >> +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) >> + >> +#define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) >> +#define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) >> + >> #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) >> #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) >> #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) >> @@ -121,6 +130,12 @@ enum acer_wmi_predator_v4_sensor_id { >> ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, >> }; >> >> +enum acer_wmi_gaming_fan_mode { >> + ACER_WMID_FAN_MODE_AUTO = 0x01, >> + ACER_WMID_FAN_MODE_TURBO = 0x02, >> + ACER_WMID_FAN_MODE_CUSTOM = 0x03, >> +}; >> + >> enum acer_wmi_predator_v4_oc { >> ACER_WMID_OC_NORMAL = 0x0000, >> ACER_WMID_OC_TURBO = 0x0002, >> @@ -1565,9 +1580,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) >> case ACER_CAP_TURBO_LED: >> method_id = ACER_WMID_SET_GAMING_LED_METHODID; >> break; >> - case ACER_CAP_TURBO_FAN: >> - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; >> - break; >> default: >> return AE_BAD_PARAMETER; >> } >> @@ -1618,25 +1630,42 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) >> return 0; >> } >> >> +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) >> +{ >> + acpi_status status; >> + u64 input = 0; >> + u64 result; >> + >> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); >> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK, mode_bitmap); >> + >> + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, >> + &result); >> + if (ACPI_FAILURE(status)) >> + return -EIO; >> + >> + /* TODO: Proper error handling */ >> + pr_notice("Fan behavior return status: %llu\n", result); >> + >> + return 0; >> +} >> + >> static void WMID_gaming_set_fan_mode(u8 fan_mode) >> { >> - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ >> - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; >> - int i; >> - >> - if (quirks->cpu_fans > 0) >> - gpu_fan_config2 |= 1; >> - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) >> - gpu_fan_config2 |= 1 << (i + 1); > This was not replicated bellow. Just to be sure, are there no fans at > BIT(1) and BIT(2)? AFAIK the Acer OEM software support the following fans: - CPU (BIT(0)) - GPU 1 (BIT(3)) - GPU 2 (BIT(4), but untested) The other bits seem to be unused. Thanks, Armin Wolf >> - for (i = 0; i < quirks->gpu_fans; ++i) >> - gpu_fan_config2 |= 1 << (i + 3); >> - if (quirks->cpu_fans > 0) >> - gpu_fan_config1 |= fan_mode; >> - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) >> - gpu_fan_config1 |= fan_mode << (2 * i + 2); > Same as above. > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior 2025-02-15 17:40 ` Armin Wolf @ 2025-02-15 18:07 ` Kurt Borja 2025-02-15 18:37 ` Armin Wolf 0 siblings, 1 reply; 10+ messages in thread From: Kurt Borja @ 2025-02-15 18:07 UTC (permalink / raw) To: Armin Wolf, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel On Sat Feb 15, 2025 at 12:40 PM -05, Armin Wolf wrote: > Am 15.02.25 um 02:30 schrieb Kurt Borja: > >> Hi Armin, >> >> On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: >>> After studying the linuwu_sense driver >>> (https://github.com/0x7375646F/Linuwu-Sense) i was able to understand >>> the meaning of the SetGamingFanBehavior() WMI method: >>> >>> - the first 16-bit are a bitmap of all fans affected by a fan behavior >>> change request. >>> >>> - the next 8 bits contain four fan mode fields (2-bit), each being >>> associated with a bit inside the fan bitmap. >>> >>> There are three fan modes: auto, turbo and custom. >>> >>> Use this newfound knowledge to fix the turbo fan handling by setting >>> the correct bits before calling SetGamingFanBehavior(). Also check >>> the result of the WMI method call and return an error should the ACPI >>> firmware signal failure. >>> >>> Signed-off-by: Armin Wolf <W_Armin@gmx.de> >>> --- >>> drivers/platform/x86/acer-wmi.c | 75 +++++++++++++++++++++++---------- >>> 1 file changed, 52 insertions(+), 23 deletions(-) >>> >>> -- >>> 2.39.5 >>> >>> diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c >>> index 69336bd778ee..f20a882e3650 100644 >>> --- a/drivers/platform/x86/acer-wmi.c >>> +++ b/drivers/platform/x86/acer-wmi.c >>> @@ -68,10 +68,19 @@ MODULE_LICENSE("GPL"); >>> #define ACER_WMID_SET_GAMING_LED_METHODID 2 >>> #define ACER_WMID_GET_GAMING_LED_METHODID 4 >>> #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 >>> -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 >>> +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 >>> #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 >>> #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 >>> >>> +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) >>> +#define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) >>> + >>> +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) >>> +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) >>> + >>> +#define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) >>> +#define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) >>> + >>> #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) >>> #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) >>> #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) >>> @@ -121,6 +130,12 @@ enum acer_wmi_predator_v4_sensor_id { >>> ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, >>> }; >>> >>> +enum acer_wmi_gaming_fan_mode { >>> + ACER_WMID_FAN_MODE_AUTO = 0x01, >>> + ACER_WMID_FAN_MODE_TURBO = 0x02, >>> + ACER_WMID_FAN_MODE_CUSTOM = 0x03, >>> +}; >>> + >>> enum acer_wmi_predator_v4_oc { >>> ACER_WMID_OC_NORMAL = 0x0000, >>> ACER_WMID_OC_TURBO = 0x0002, >>> @@ -1565,9 +1580,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) >>> case ACER_CAP_TURBO_LED: >>> method_id = ACER_WMID_SET_GAMING_LED_METHODID; >>> break; >>> - case ACER_CAP_TURBO_FAN: >>> - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; >>> - break; >>> default: >>> return AE_BAD_PARAMETER; >>> } >>> @@ -1618,25 +1630,42 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) >>> return 0; >>> } >>> >>> +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) >>> +{ >>> + acpi_status status; >>> + u64 input = 0; >>> + u64 result; >>> + >>> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); >>> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK, mode_bitmap); >>> + >>> + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, >>> + &result); >>> + if (ACPI_FAILURE(status)) >>> + return -EIO; >>> + >>> + /* TODO: Proper error handling */ >>> + pr_notice("Fan behavior return status: %llu\n", result); >>> + >>> + return 0; >>> +} >>> + >>> static void WMID_gaming_set_fan_mode(u8 fan_mode) >>> { >>> - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ >>> - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; >>> - int i; >>> - >>> - if (quirks->cpu_fans > 0) >>> - gpu_fan_config2 |= 1; >>> - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) >>> - gpu_fan_config2 |= 1 << (i + 1); >> This was not replicated bellow. Just to be sure, are there no fans at >> BIT(1) and BIT(2)? > > AFAIK the Acer OEM software support the following fans: > > - CPU (BIT(0)) > - GPU 1 (BIT(3)) > - GPU 2 (BIT(4), but untested) > > The other bits seem to be unused. Interesting. I ask because quirks->cpu_fans + quirks->gpu_fans is currently always 2, so the line two `-` lines I referenced make the following equivalent operation: fan_bitmap |= BIT(1); mode_bitmap |= FIELD_PREP(GENMASK(3, 2), fan_mode); fan_bitmap |= BIT(2); mode_bitmap |= FIELD_PREP(GENMASK(5, 4), fan_mode); So if any model has fans at BIT(1), BIT(2) this may cause regressions if the behavior is not mimicked. Am I missing something? Anyway, your explaination for how this method works makes a lot of sense, so it is weird that the original author of this is summing the number of fans and setting this bits in the first place. -- ~ Kurt > > Thanks, > Armin Wolf > >>> - for (i = 0; i < quirks->gpu_fans; ++i) >>> - gpu_fan_config2 |= 1 << (i + 3); >>> - if (quirks->cpu_fans > 0) >>> - gpu_fan_config1 |= fan_mode; >>> - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) >>> - gpu_fan_config1 |= fan_mode << (2 * i + 2); >> Same as above. >> ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior 2025-02-15 18:07 ` Kurt Borja @ 2025-02-15 18:37 ` Armin Wolf 0 siblings, 0 replies; 10+ messages in thread From: Armin Wolf @ 2025-02-15 18:37 UTC (permalink / raw) To: Kurt Borja, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Am 15.02.25 um 19:07 schrieb Kurt Borja: > On Sat Feb 15, 2025 at 12:40 PM -05, Armin Wolf wrote: >> Am 15.02.25 um 02:30 schrieb Kurt Borja: >> >>> Hi Armin, >>> >>> On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: >>>> After studying the linuwu_sense driver >>>> (https://github.com/0x7375646F/Linuwu-Sense) i was able to understand >>>> the meaning of the SetGamingFanBehavior() WMI method: >>>> >>>> - the first 16-bit are a bitmap of all fans affected by a fan behavior >>>> change request. >>>> >>>> - the next 8 bits contain four fan mode fields (2-bit), each being >>>> associated with a bit inside the fan bitmap. >>>> >>>> There are three fan modes: auto, turbo and custom. >>>> >>>> Use this newfound knowledge to fix the turbo fan handling by setting >>>> the correct bits before calling SetGamingFanBehavior(). Also check >>>> the result of the WMI method call and return an error should the ACPI >>>> firmware signal failure. >>>> >>>> Signed-off-by: Armin Wolf <W_Armin@gmx.de> >>>> --- >>>> drivers/platform/x86/acer-wmi.c | 75 +++++++++++++++++++++++---------- >>>> 1 file changed, 52 insertions(+), 23 deletions(-) >>>> >>>> -- >>>> 2.39.5 >>>> >>>> diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c >>>> index 69336bd778ee..f20a882e3650 100644 >>>> --- a/drivers/platform/x86/acer-wmi.c >>>> +++ b/drivers/platform/x86/acer-wmi.c >>>> @@ -68,10 +68,19 @@ MODULE_LICENSE("GPL"); >>>> #define ACER_WMID_SET_GAMING_LED_METHODID 2 >>>> #define ACER_WMID_GET_GAMING_LED_METHODID 4 >>>> #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 >>>> -#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR 14 >>>> +#define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 >>>> #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 >>>> #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 >>>> >>>> +#define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) >>>> +#define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) >>>> + >>>> +#define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) >>>> +#define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) >>>> + >>>> +#define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) >>>> +#define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) >>>> + >>>> #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) >>>> #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) >>>> #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) >>>> @@ -121,6 +130,12 @@ enum acer_wmi_predator_v4_sensor_id { >>>> ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, >>>> }; >>>> >>>> +enum acer_wmi_gaming_fan_mode { >>>> + ACER_WMID_FAN_MODE_AUTO = 0x01, >>>> + ACER_WMID_FAN_MODE_TURBO = 0x02, >>>> + ACER_WMID_FAN_MODE_CUSTOM = 0x03, >>>> +}; >>>> + >>>> enum acer_wmi_predator_v4_oc { >>>> ACER_WMID_OC_NORMAL = 0x0000, >>>> ACER_WMID_OC_TURBO = 0x0002, >>>> @@ -1565,9 +1580,6 @@ static acpi_status WMID_gaming_set_u64(u64 value, u32 cap) >>>> case ACER_CAP_TURBO_LED: >>>> method_id = ACER_WMID_SET_GAMING_LED_METHODID; >>>> break; >>>> - case ACER_CAP_TURBO_FAN: >>>> - method_id = ACER_WMID_SET_GAMING_FAN_BEHAVIOR; >>>> - break; >>>> default: >>>> return AE_BAD_PARAMETER; >>>> } >>>> @@ -1618,25 +1630,42 @@ static int WMID_gaming_get_sys_info(u32 command, u64 *out) >>>> return 0; >>>> } >>>> >>>> +static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) >>>> +{ >>>> + acpi_status status; >>>> + u64 input = 0; >>>> + u64 result; >>>> + >>>> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); >>>> + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK, mode_bitmap); >>>> + >>>> + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID, input, >>>> + &result); >>>> + if (ACPI_FAILURE(status)) >>>> + return -EIO; >>>> + >>>> + /* TODO: Proper error handling */ >>>> + pr_notice("Fan behavior return status: %llu\n", result); >>>> + >>>> + return 0; >>>> +} >>>> + >>>> static void WMID_gaming_set_fan_mode(u8 fan_mode) >>>> { >>>> - /* fan_mode = 1 is used for auto, fan_mode = 2 used for turbo*/ >>>> - u64 gpu_fan_config1 = 0, gpu_fan_config2 = 0; >>>> - int i; >>>> - >>>> - if (quirks->cpu_fans > 0) >>>> - gpu_fan_config2 |= 1; >>>> - for (i = 0; i < (quirks->cpu_fans + quirks->gpu_fans); ++i) >>>> - gpu_fan_config2 |= 1 << (i + 1); >>> This was not replicated bellow. Just to be sure, are there no fans at >>> BIT(1) and BIT(2)? >> AFAIK the Acer OEM software support the following fans: >> >> - CPU (BIT(0)) >> - GPU 1 (BIT(3)) >> - GPU 2 (BIT(4), but untested) >> >> The other bits seem to be unused. > Interesting. > > I ask because quirks->cpu_fans + quirks->gpu_fans is currently always 2, > so the line two `-` lines I referenced make the following equivalent > operation: > > fan_bitmap |= BIT(1); > mode_bitmap |= FIELD_PREP(GENMASK(3, 2), fan_mode); > > fan_bitmap |= BIT(2); > mode_bitmap |= FIELD_PREP(GENMASK(5, 4), fan_mode); > > So if any model has fans at BIT(1), BIT(2) this may cause regressions if > the behavior is not mimicked. > > Am I missing something? > > Anyway, your explaination for how this method works makes a lot of > sense, so it is weird that the original author of this is summing the > number of fans and setting this bits in the first place. > I do not know why the original code assigned BIT(1) and BIT(2), but i know for sure that no other (out-of-tree) implementation does this. I suspect that some models just ignore those unused bits, while others return an error. This might explain why the turbo fan functionality does not work on some machines. Should we find a model in the future with more fans then we can extend the fan control code as needed. For now the risk of regressions should be low since all models inside the whitelist have only a single CPU and GPU fan. Thanks, Armin Wolf ^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support 2025-02-14 22:13 [RFC PATCH 0/3] platform/x86: acer-wmi: Add fan control support Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior Armin Wolf @ 2025-02-14 22:13 ` Armin Wolf 2025-02-15 1:33 ` Kurt Borja 2025-02-14 22:13 ` [RFC PATCH 3/3] platform/x86: acer-wmi: Enable fan control for PH16-72 and PT14-51 Armin Wolf 2 siblings, 1 reply; 10+ messages in thread From: Armin Wolf @ 2025-02-14 22:13 UTC (permalink / raw) To: jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Add support for controlling the fan speed using the SetGamingFanSpeed() and GetGamingFanSpeed() WMI methods. This feature is only enabled if the machine has ACER_CAP_PWM enabled and depend on ACER_CAP_HWMON for detecting the number of available fans. Signed-off-by: Armin Wolf <W_Armin@gmx.de> --- drivers/platform/x86/acer-wmi.c | 222 +++++++++++++++++++++++++++++++- 1 file changed, 220 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index f20a882e3650..e24f5a323f95 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -12,10 +12,12 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/init.h> #include <linux/types.h> #include <linux/dmi.h> +#include <linux/fixp-arith.h> #include <linux/backlight.h> #include <linux/leds.h> #include <linux/platform_device.h> @@ -30,6 +32,7 @@ #include <linux/input/sparse-keymap.h> #include <acpi/video.h> #include <linux/hwmon.h> +#include <linux/unaligned.h> #include <linux/units.h> #include <linux/unaligned.h> #include <linux/bitfield.h> @@ -69,11 +72,16 @@ MODULE_LICENSE("GPL"); #define ACER_WMID_GET_GAMING_LED_METHODID 4 #define ACER_WMID_GET_GAMING_SYS_INFO_METHODID 5 #define ACER_WMID_SET_GAMING_FAN_BEHAVIOR_METHODID 14 +#define ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID 15 +#define ACER_WMID_SET_GAMING_FAN_SPEED_METHODID 16 +#define ACER_WMID_GET_GAMING_FAN_SPEED_METHODID 17 #define ACER_WMID_SET_GAMING_MISC_SETTING_METHODID 22 #define ACER_WMID_GET_GAMING_MISC_SETTING_METHODID 23 +#define ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_FAN_BEHAVIOR_ID_MASK GENMASK_ULL(15, 0) #define ACER_GAMING_FAN_BEHAVIOR_SET_MODE_MASK GENMASK_ULL(23, 16) +#define ACER_GAMING_FAN_BEHAVIOR_GET_MODE_MASK GENMASK_ULL(23, 8) #define ACER_GAMING_FAN_BEHAVIOR_CPU BIT(0) #define ACER_GAMING_FAN_BEHAVIOR_GPU BIT(3) @@ -81,6 +89,10 @@ MODULE_LICENSE("GPL"); #define ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK GENMASK(1, 0) #define ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK GENMASK(7, 6) +#define ACER_GAMING_FAN_SPEED_STATUS_MASK GENMASK_ULL(7, 0) +#define ACER_GAMING_FAN_SPEED_ID_MASK GENMASK_ULL(7, 0) +#define ACER_GAMING_FAN_SPEED_VALUE_MASK GENMASK_ULL(15, 8) + #define ACER_GAMING_MISC_SETTING_STATUS_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_INDEX_MASK GENMASK_ULL(7, 0) #define ACER_GAMING_MISC_SETTING_VALUE_MASK GENMASK_ULL(15, 8) @@ -130,6 +142,11 @@ enum acer_wmi_predator_v4_sensor_id { ACER_WMID_SENSOR_GPU_TEMPERATURE = 0x0A, }; +enum acer_wmi_gaming_fan_id { + ACER_WMID_CPU_FAN = 0x01, + ACER_WMID_GPU_FAN = 0x04, +}; + enum acer_wmi_gaming_fan_mode { ACER_WMID_FAN_MODE_AUTO = 0x01, ACER_WMID_FAN_MODE_TURBO = 0x02, @@ -292,6 +309,7 @@ struct hotkey_function_type_aa { #define ACER_CAP_TURBO_FAN BIT(9) #define ACER_CAP_PLATFORM_PROFILE BIT(10) #define ACER_CAP_HWMON BIT(11) +#define ACER_CAP_PWM BIT(12) /* * Interface type flags @@ -386,6 +404,7 @@ struct quirk_entry { u8 cpu_fans; u8 gpu_fans; u8 predator_v4; + u8 pwm; }; static struct quirk_entry *quirks; @@ -405,6 +424,9 @@ static void __init set_quirks(void) if (quirks->predator_v4) interface->capability |= ACER_CAP_PLATFORM_PROFILE | ACER_CAP_HWMON; + + if (quirks->pwm) + interface->capability |= ACER_CAP_PWM; } static int __init dmi_matched(const struct dmi_system_id *dmi) @@ -1650,6 +1672,27 @@ static int WMID_gaming_set_fan_behavior(u16 fan_bitmap, u8 mode_bitmap) return 0; } +static int WMID_gaming_get_fan_behavior(u16 fan_bitmap, u8 *mode_bitmap) +{ + acpi_status status; + u32 input = 0; + u64 result; + + input |= FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_ID_MASK, fan_bitmap); + status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_BEHAVIOR_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + /* The return status must be zero for the operation to have succeeded */ + if (FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_STATUS_MASK, result)) + return -EIO; + + *mode_bitmap = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GET_MODE_MASK, result); + + return 0; +} + static void WMID_gaming_set_fan_mode(u8 fan_mode) { u16 mode_bitmap = 0; @@ -1668,6 +1711,55 @@ static void WMID_gaming_set_fan_mode(u8 fan_mode) WMID_gaming_set_fan_behavior(fan_bitmap, mode_bitmap); } +static int WMID_gaming_set_gaming_fan_speed(u8 fan, u8 speed) +{ + acpi_status status; + u64 input = 0; + u64 result; + + if (speed > 100) + return -EINVAL; + + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan); + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_VALUE_MASK, speed); + + status = WMI_gaming_execute_u64(ACER_WMID_SET_GAMING_FAN_SPEED_METHODID, input, &result); + if (ACPI_FAILURE(status)) + return -EIO; + + switch (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) { + case 0x00: + return 0; + case 0x01: + return -ENODEV; + case 0x02: + return -EINVAL; + default: + return -ENXIO; + } +} + +static int WMID_gaming_get_gaming_fan_speed(u8 fan, u8 *speed) +{ + acpi_status status; + u32 input = 0; + u64 result; + + input |= FIELD_PREP(ACER_GAMING_FAN_SPEED_ID_MASK, fan); + + status = WMI_gaming_execute_u32_u64(ACER_WMID_GET_GAMING_FAN_SPEED_METHODID, input, + &result); + if (ACPI_FAILURE(status)) + return -EIO; + + if (FIELD_GET(ACER_GAMING_FAN_SPEED_STATUS_MASK, result)) + return -ENODEV; + + *speed = FIELD_GET(ACER_GAMING_FAN_SPEED_VALUE_MASK, result); + + return 0; +} + static int WMID_gaming_set_misc_setting(enum acer_wmi_gaming_misc_setting setting, u8 value) { acpi_status status; @@ -2839,6 +2931,16 @@ static const enum acer_wmi_predator_v4_sensor_id acer_wmi_fan_channel_to_sensor_ [1] = ACER_WMID_SENSOR_GPU_FAN_SPEED, }; +static const enum acer_wmi_gaming_fan_id acer_wmi_fan_channel_to_fan_id[] = { + [0] = ACER_WMID_CPU_FAN, + [1] = ACER_WMID_GPU_FAN, +}; + +static const u16 acer_wmi_fan_channel_to_fan_bitmap[] = { + [0] = ACER_GAMING_FAN_BEHAVIOR_CPU, + [1] = ACER_GAMING_FAN_BEHAVIOR_GPU, +}; + static umode_t acer_wmi_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -2850,6 +2952,11 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data, case hwmon_temp: sensor_id = acer_wmi_temp_channel_to_sensor_id[channel]; break; + case hwmon_pwm: + if (!has_cap(ACER_CAP_PWM)) + return 0; + + fallthrough; case hwmon_fan: sensor_id = acer_wmi_fan_channel_to_sensor_id[channel]; break; @@ -2857,8 +2964,12 @@ static umode_t acer_wmi_hwmon_is_visible(const void *data, return 0; } - if (*supported_sensors & BIT(sensor_id - 1)) + if (*supported_sensors & BIT(sensor_id - 1)) { + if (type == hwmon_pwm) + return 0644; + return 0444; + } return 0; } @@ -2867,8 +2978,10 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING; + u8 fan, speed, mode_bitmap; + u16 fan_bitmap; + int mode, ret; u64 result; - int ret; switch (type) { case hwmon_temp: @@ -2892,6 +3005,106 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, *val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result); return 0; + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + fan = acer_wmi_fan_channel_to_fan_id[channel]; + ret = WMID_gaming_get_gaming_fan_speed(fan, &speed); + if (ret < 0) + return ret; + + *val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed); + return 0; + case hwmon_pwm_enable: + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; + ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode_bitmap); + if (ret < 0) + return ret; + + switch (channel) { + case 0: + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, + mode_bitmap); + break; + case 1: + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, + mode_bitmap); + break; + default: + return -EINVAL; + } + + switch (mode) { + case ACER_WMID_FAN_MODE_AUTO: + *val = 2; + return 0; + case ACER_WMID_FAN_MODE_TURBO: + *val = 0; + return 0; + case ACER_WMID_FAN_MODE_CUSTOM: + *val = 1; + return 0; + default: + return -ENXIO; + } + default: + return -EOPNOTSUPP; + } + default: + return -EOPNOTSUPP; + } +} + +static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + u8 fan, speed, mode_bitmap; + u16 fan_bitmap; + int mode; + + switch (type) { + case hwmon_pwm: + switch (attr) { + case hwmon_pwm_input: + fan = acer_wmi_fan_channel_to_fan_id[channel]; + speed = fixp_linear_interpolate(0, 0, U8_MAX, 100, + clamp_val(val, 0, U8_MAX)); + + return WMID_gaming_set_gaming_fan_speed(fan, speed); + case hwmon_pwm_mode: + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; + + switch (val) { + case 0: + mode = ACER_WMID_FAN_MODE_TURBO; + break; + case 1: + mode = ACER_WMID_FAN_MODE_CUSTOM; + break; + case 2: + mode = ACER_WMID_FAN_MODE_AUTO; + break; + default: + return -EINVAL; + } + + switch (channel) { + case 0: + mode_bitmap = FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, + mode); + break; + case 1: + mode_bitmap = FIELD_PREP(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, + mode); + break; + default: + return -EINVAL; + } + + return WMID_gaming_set_fan_behavior(fan_bitmap, mode_bitmap); + default: + return -EOPNOTSUPP; + } default: return -EOPNOTSUPP; } @@ -2907,11 +3120,16 @@ static const struct hwmon_channel_info *const acer_wmi_hwmon_info[] = { HWMON_F_INPUT, HWMON_F_INPUT ), + HWMON_CHANNEL_INFO(pwm, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, + HWMON_PWM_INPUT | HWMON_PWM_ENABLE + ), NULL }; static const struct hwmon_ops acer_wmi_hwmon_ops = { .read = acer_wmi_hwmon_read, + .write = acer_wmi_hwmon_write, .is_visible = acer_wmi_hwmon_is_visible, }; -- 2.39.5 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support 2025-02-14 22:13 ` [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support Armin Wolf @ 2025-02-15 1:33 ` Kurt Borja 2025-02-15 17:47 ` Armin Wolf 0 siblings, 1 reply; 10+ messages in thread From: Kurt Borja @ 2025-02-15 1:33 UTC (permalink / raw) To: Armin Wolf, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: > Add support for controlling the fan speed using the > SetGamingFanSpeed() and GetGamingFanSpeed() WMI methods. > > This feature is only enabled if the machine has ACER_CAP_PWM enabled > and depend on ACER_CAP_HWMON for detecting the number of available > fans. > > Signed-off-by: Armin Wolf <W_Armin@gmx.de> > --- > drivers/platform/x86/acer-wmi.c | 222 +++++++++++++++++++++++++++++++- > 1 file changed, 220 insertions(+), 2 deletions(-) > > -- > 2.39.5 > > diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c > index f20a882e3650..e24f5a323f95 100644 > --- a/drivers/platform/x86/acer-wmi.c > +++ b/drivers/platform/x86/acer-wmi.c > @@ -12,10 +12,12 @@ > #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > #include <linux/kernel.h> > +#include <linux/minmax.h> > #include <linux/module.h> > #include <linux/init.h> > #include <linux/types.h> > #include <linux/dmi.h> > +#include <linux/fixp-arith.h> I didn't know about this, thanks! > #include <linux/backlight.h> > #include <linux/leds.h> > #include <linux/platform_device.h> > @@ -30,6 +32,7 @@ > #include <linux/input/sparse-keymap.h> > #include <acpi/video.h> > #include <linux/hwmon.h> > +#include <linux/unaligned.h> Duplicated include. > #include <linux/units.h> > #include <linux/unaligned.h> > #include <linux/bitfield.h> ... > @@ -2867,8 +2978,10 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, > u32 attr, int channel, long *val) > { > u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING; > + u8 fan, speed, mode_bitmap; > + u16 fan_bitmap; > + int mode, ret; > u64 result; > - int ret; > > switch (type) { > case hwmon_temp: > @@ -2892,6 +3005,106 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, > > *val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result); > return 0; > + case hwmon_pwm: > + switch (attr) { > + case hwmon_pwm_input: > + fan = acer_wmi_fan_channel_to_fan_id[channel]; > + ret = WMID_gaming_get_gaming_fan_speed(fan, &speed); > + if (ret < 0) > + return ret; > + > + *val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed); > + return 0; > + case hwmon_pwm_enable: > + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; > + ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode_bitmap); > + if (ret < 0) > + return ret; > + > + switch (channel) { > + case 0: > + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, > + mode_bitmap); > + break; > + case 1: > + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, > + mode_bitmap); > + break; > + default: > + return -EINVAL; > + } > + > + switch (mode) { > + case ACER_WMID_FAN_MODE_AUTO: > + *val = 2; > + return 0; > + case ACER_WMID_FAN_MODE_TURBO: > + *val = 0; > + return 0; > + case ACER_WMID_FAN_MODE_CUSTOM: > + *val = 1; > + return 0; > + default: > + return -ENXIO; > + } > + default: > + return -EOPNOTSUPP; > + } > + default: > + return -EOPNOTSUPP; > + } > +} > + > +static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, > + u32 attr, int channel, long val) > +{ > + u8 fan, speed, mode_bitmap; > + u16 fan_bitmap; > + int mode; > + > + switch (type) { > + case hwmon_pwm: > + switch (attr) { > + case hwmon_pwm_input: > + fan = acer_wmi_fan_channel_to_fan_id[channel]; > + speed = fixp_linear_interpolate(0, 0, U8_MAX, 100, > + clamp_val(val, 0, U8_MAX)); > + > + return WMID_gaming_set_gaming_fan_speed(fan, speed); > + case hwmon_pwm_mode: hwmon_pwm_enable? Other than that: Reviewed-by: Kurt Borja <kuurtb@gmail.com> > <snip> ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support 2025-02-15 1:33 ` Kurt Borja @ 2025-02-15 17:47 ` Armin Wolf 0 siblings, 0 replies; 10+ messages in thread From: Armin Wolf @ 2025-02-15 17:47 UTC (permalink / raw) To: Kurt Borja, jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Am 15.02.25 um 02:33 schrieb Kurt Borja: > On Fri Feb 14, 2025 at 5:13 PM -05, Armin Wolf wrote: >> Add support for controlling the fan speed using the >> SetGamingFanSpeed() and GetGamingFanSpeed() WMI methods. >> >> This feature is only enabled if the machine has ACER_CAP_PWM enabled >> and depend on ACER_CAP_HWMON for detecting the number of available >> fans. >> >> Signed-off-by: Armin Wolf <W_Armin@gmx.de> >> --- >> drivers/platform/x86/acer-wmi.c | 222 +++++++++++++++++++++++++++++++- >> 1 file changed, 220 insertions(+), 2 deletions(-) >> >> -- >> 2.39.5 >> >> diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c >> index f20a882e3650..e24f5a323f95 100644 >> --- a/drivers/platform/x86/acer-wmi.c >> +++ b/drivers/platform/x86/acer-wmi.c >> @@ -12,10 +12,12 @@ >> #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt >> >> #include <linux/kernel.h> >> +#include <linux/minmax.h> >> #include <linux/module.h> >> #include <linux/init.h> >> #include <linux/types.h> >> #include <linux/dmi.h> >> +#include <linux/fixp-arith.h> > I didn't know about this, thanks! > >> #include <linux/backlight.h> >> #include <linux/leds.h> >> #include <linux/platform_device.h> >> @@ -30,6 +32,7 @@ >> #include <linux/input/sparse-keymap.h> >> #include <acpi/video.h> >> #include <linux/hwmon.h> >> +#include <linux/unaligned.h> > Duplicated include. > >> #include <linux/units.h> >> #include <linux/unaligned.h> >> #include <linux/bitfield.h> > ... >> @@ -2867,8 +2978,10 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, >> u32 attr, int channel, long *val) >> { >> u64 command = ACER_WMID_CMD_GET_PREDATOR_V4_SENSOR_READING; >> + u8 fan, speed, mode_bitmap; >> + u16 fan_bitmap; >> + int mode, ret; >> u64 result; >> - int ret; >> >> switch (type) { >> case hwmon_temp: >> @@ -2892,6 +3005,106 @@ static int acer_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type, >> >> *val = FIELD_GET(ACER_PREDATOR_V4_SENSOR_READING_BIT_MASK, result); >> return 0; >> + case hwmon_pwm: >> + switch (attr) { >> + case hwmon_pwm_input: >> + fan = acer_wmi_fan_channel_to_fan_id[channel]; >> + ret = WMID_gaming_get_gaming_fan_speed(fan, &speed); >> + if (ret < 0) >> + return ret; >> + >> + *val = fixp_linear_interpolate(0, 0, 100, U8_MAX, speed); >> + return 0; >> + case hwmon_pwm_enable: >> + fan_bitmap = acer_wmi_fan_channel_to_fan_bitmap[channel]; >> + ret = WMID_gaming_get_fan_behavior(fan_bitmap, &mode_bitmap); >> + if (ret < 0) >> + return ret; >> + >> + switch (channel) { >> + case 0: >> + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_CPU_MODE_MASK, >> + mode_bitmap); >> + break; >> + case 1: >> + mode = FIELD_GET(ACER_GAMING_FAN_BEHAVIOR_GPU_MODE_MASK, >> + mode_bitmap); >> + break; >> + default: >> + return -EINVAL; >> + } >> + >> + switch (mode) { >> + case ACER_WMID_FAN_MODE_AUTO: >> + *val = 2; >> + return 0; >> + case ACER_WMID_FAN_MODE_TURBO: >> + *val = 0; >> + return 0; >> + case ACER_WMID_FAN_MODE_CUSTOM: >> + *val = 1; >> + return 0; >> + default: >> + return -ENXIO; >> + } >> + default: >> + return -EOPNOTSUPP; >> + } >> + default: >> + return -EOPNOTSUPP; >> + } >> +} >> + >> +static int acer_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type, >> + u32 attr, int channel, long val) >> +{ >> + u8 fan, speed, mode_bitmap; >> + u16 fan_bitmap; >> + int mode; >> + >> + switch (type) { >> + case hwmon_pwm: >> + switch (attr) { >> + case hwmon_pwm_input: >> + fan = acer_wmi_fan_channel_to_fan_id[channel]; >> + speed = fixp_linear_interpolate(0, 0, U8_MAX, 100, >> + clamp_val(val, 0, U8_MAX)); >> + >> + return WMID_gaming_set_gaming_fan_speed(fan, speed); >> + case hwmon_pwm_mode: > hwmon_pwm_enable? > > Other than that: > > Reviewed-by: Kurt Borja <kuurtb@gmail.com> Thanks for spotting this mistakes, i send an updated series without those flaws. Thanks, Armin Wolf >> <snip> ^ permalink raw reply [flat|nested] 10+ messages in thread
* [RFC PATCH 3/3] platform/x86: acer-wmi: Enable fan control for PH16-72 and PT14-51 2025-02-14 22:13 [RFC PATCH 0/3] platform/x86: acer-wmi: Add fan control support Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support Armin Wolf @ 2025-02-14 22:13 ` Armin Wolf 2 siblings, 0 replies; 10+ messages in thread From: Armin Wolf @ 2025-02-14 22:13 UTC (permalink / raw) To: jlee, basak.sb2006, rayanmargham4 Cc: hdegoede, ilpo.jarvinen, platform-driver-x86, linux-kernel Both machines support the necessary WMI methods, so enable fan control for them. Signed-off-by: Armin Wolf <W_Armin@gmx.de> --- drivers/platform/x86/acer-wmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index e24f5a323f95..05cbe8f96f21 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -466,6 +466,7 @@ static struct quirk_entry quirk_acer_predator_ph16_72 = { .cpu_fans = 1, .gpu_fans = 1, .predator_v4 = 1, + .pwm = 1, }; static struct quirk_entry quirk_acer_predator_pt14_51 = { @@ -473,6 +474,7 @@ static struct quirk_entry quirk_acer_predator_pt14_51 = { .cpu_fans = 1, .gpu_fans = 1, .predator_v4 = 1, + .pwm = 1, }; static struct quirk_entry quirk_acer_predator_v4 = { -- 2.39.5 ^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-02-15 18:37 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-02-14 22:13 [RFC PATCH 0/3] platform/x86: acer-wmi: Add fan control support Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 1/3] platform/x86: acer-wmi: Fix setting of fan behavior Armin Wolf 2025-02-15 1:30 ` Kurt Borja 2025-02-15 17:40 ` Armin Wolf 2025-02-15 18:07 ` Kurt Borja 2025-02-15 18:37 ` Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 2/3] platform/x86: acer-wmi: Add fan control support Armin Wolf 2025-02-15 1:33 ` Kurt Borja 2025-02-15 17:47 ` Armin Wolf 2025-02-14 22:13 ` [RFC PATCH 3/3] platform/x86: acer-wmi: Enable fan control for PH16-72 and PT14-51 Armin Wolf
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.