Re: [PATCH] platform/x86: asus-wmi: Support setting AIPT modes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am 23.10.24 um 22:15 schrieb srinivas pandruvada:

On Wed, 2024-10-23 at 20:57 +0200, Armin Wolf wrote:
Am 23.10.24 um 19:59 schrieb Mohamed Ghanmi:

On Wed, Oct 23, 2024 at 06:31:17PM +0200, Armin Wolf wrote:
Am 23.10.24 um 16:44 schrieb Mohamed Ghanmi:

Hello !
On Sun, Oct 20, 2024 at 09:42:45PM +0200, Armin Wolf wrote:
Am 20.10.24 um 21:05 schrieb Armin Wolf:

Am 20.10.24 um 08:50 schrieb Srinivas Pandruvada:

Some recent Asus laptops are supporting ASUS Intelligent
Performance
Technology (AIPT). This solution allows users to have
maximized CPU
performance in models with a chassis providing more
thermal head room.
Refer to [1].

There are major performance issues when Linux is
installed on these
laptops compared to Windows install. One such report is
published for
Graphics benchmarks on Asus ASUS Zenbook S 14 with Lunar
Lake
processors [2].

By default, these laptops are booting in "Whisper Mode"
till OS power
management or tools change this to other AIPT mode. This
"Whisper" mode
calls to set lower maximum and minimum RAPL (Running
Average Power
Limit)
via thermal tables. On Linux this leads to lower
performance even when
platform power profile is "balanced". This "Whisper" mode
should
correspond to "quiet" mode.

So, when AIPT is present change the default mode to
"Standard" during
boot. Map the three platform power profile modes as
follows:

Power Profile Mode      AIPT mode
-----------------------------------
quiet            Whisper
balanced        Standard
performance        Performance
------------------------------------

Here AIPT mode can be detected by checking presese of
"FANL" method
under
PNP HID "PNP0C14" and UID "ATK". If AIPT mode is present,
this takes
precedence over the existing VIVO thermal policy. These
modes are set
using "FANL" method.

Although this “FANL” method is not used in the Asus WMI
driver, users
have used this method from user space [3] to set AIPT
modes. Used this
as a reference.

Link:
https://www.asus.com/content/laptop-asus-intelligent-performance-technology-aipt/
# [1]
Reported-by: Michael Larabel <Michael@xxxxxxxxxxxx>
Closes:
https://www.phoronix.com/review/lunar-lake-xe2/5 # [2]
Link:
https://github.com/dominiksalvet/asus-fan-control/issues/151
  # [3]
Tested-by: Casey Bowman <casey.g.bowman@xxxxxxxxx>
Signed-off-by: Srinivas Pandruvada
<srinivas.pandruvada@xxxxxxxxxxxxxxx>
---
     drivers/platform/x86/asus-wmi.c | 93
+++++++++++++++++++++++++++++++--
     1 file changed, 89 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/asus-wmi.c
b/drivers/platform/x86/asus-wmi.c
index 7a48220b4f5a..06689d0f98c7 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -100,6 +100,11 @@ module_param(fnlock_default, bool,
0444);
     #define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO    1
     #define
ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO    2

+#define AIPT_STANDARD                0
+#define AIPT_WHISPER                1
+#define AIPT_PERFORMANCE            2
+#define AIPT_FULL_SPEED                3
+
     #define PLATFORM_PROFILE_MAX 2

     #define USB_INTEL_XUSB2PR        0xD0
@@ -333,6 +338,9 @@ struct asus_wmi {
         struct asus_wmi_debug debug;

         struct asus_wmi_driver *driver;
+    acpi_handle acpi_mgmt_handle;
+    int asus_aipt_mode;
+    bool asus_aipt_present;
     };

     /* WMI
*********************************************************
***************/
@@ -3804,6 +3812,19 @@ static ssize_t
throttle_thermal_policy_store(struct device *dev,
     static DEVICE_ATTR_RW(throttle_thermal_policy);

     /* Platform profile
*********************************************************
**/
+static int asus_wmi_write_aipt_mode(struct asus_wmi
*asus, int
aipt_mode)
+{
+    int status;
+
+    status = acpi_execute_simple_method(asus-
acpi_mgmt_handle,
"FANL", aipt_mode);
+    if (ACPI_FAILURE(status)) {
+        acpi_handle_info(asus->acpi_mgmt_handle, "FANL
execute
failed\n");
+        return -EIO;
+    }
+
+    return 0;
+}
+
     static int asus_wmi_platform_profile_to_vivo(struct
asus_wmi *asus,
int mode)
     {
         bool vivo;
@@ -3844,6 +3865,26 @@ static int
asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi
*asus, int m
         return mode;
     }

+static int asus_wmi_aipt_platform_profile_get(struct
asus_wmi *asus,
+                          enum platform_profile_option
*profile)
+{
+    switch (asus->asus_aipt_mode) {
+    case AIPT_STANDARD:
+        *profile = PLATFORM_PROFILE_BALANCED;
+        break;
+    case AIPT_PERFORMANCE:
+        *profile = PLATFORM_PROFILE_PERFORMANCE;
+        break;
+    case AIPT_WHISPER:
+        *profile = PLATFORM_PROFILE_QUIET;
+        break;
+    default:
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
     static int asus_wmi_platform_profile_get(struct
platform_profile_handler *pprof,
                         enum platform_profile_option
*profile)
     {
@@ -3851,6 +3892,10 @@ static int
asus_wmi_platform_profile_get(struct
platform_profile_handler *pprof,
         int tp;

         asus = container_of(pprof, struct asus_wmi,
platform_profile_handler);
+
+    if (asus->asus_aipt_present)
+        return asus_wmi_aipt_platform_profile_get(asus,
profile);
+
         tp = asus->throttle_thermal_policy_mode;

         switch
(asus_wmi_platform_profile_mode_from_vivo(asus, tp)) {
@@ -3874,26 +3919,42 @@ static int
asus_wmi_platform_profile_set(struct
platform_profile_handler *pprof,
                         enum platform_profile_option
profile)
     {
         struct asus_wmi *asus;
-    int tp;
+    int ret = 0, tp, aipt_mode;

         asus = container_of(pprof, struct asus_wmi,
platform_profile_handler);

         switch (profile) {
         case PLATFORM_PROFILE_PERFORMANCE:
             tp = ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
+        aipt_mode = AIPT_PERFORMANCE;
             break;
         case PLATFORM_PROFILE_BALANCED:
             tp = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+        aipt_mode = AIPT_STANDARD;
             break;
         case PLATFORM_PROFILE_QUIET:
             tp = ASUS_THROTTLE_THERMAL_POLICY_SILENT;
+        aipt_mode = AIPT_WHISPER;
             break;
         default:
             return -EOPNOTSUPP;
         }

-    asus->throttle_thermal_policy_mode =
asus_wmi_platform_profile_to_vivo(asus, tp);
-    return throttle_thermal_policy_write(asus);
+    if (asus->asus_aipt_present) {
+        ret = asus_wmi_write_aipt_mode(asus, aipt_mode);
+        if (!ret) {
+            asus->asus_aipt_mode = aipt_mode;
+            goto skip_vivo;
+        }
+    }
+
+    if (asus->throttle_thermal_policy_dev) {
+        asus->throttle_thermal_policy_mode =
asus_wmi_platform_profile_to_vivo(asus, tp);
+        ret = throttle_thermal_policy_write(asus);
+    }
+
+skip_vivo:
+    return ret;
     }

     static int platform_profile_setup(struct asus_wmi
*asus)
@@ -3905,7 +3966,7 @@ static int
platform_profile_setup(struct
asus_wmi *asus)
          * Not an error if a component platform_profile
relies on is
unavailable
          * so early return, skipping the setup of
platform_profile.
          */
-    if (!asus->throttle_thermal_policy_dev)
+    if (!asus->throttle_thermal_policy_dev && !asus-
asus_aipt_present)
             return 0;

         dev_info(dev, "Using throttle_thermal_policy for
platform_profile support\n");
@@ -4538,6 +4599,7 @@ static int
asus_wmi_sysfs_init(struct
platform_device *device)
     static int asus_wmi_platform_init(struct asus_wmi
*asus)
     {
         struct device *dev = &asus->platform_device->dev;
+    struct acpi_device *adev;
         char *wmi_uid;
         int rv;

@@ -4593,6 +4655,29 @@ static int
asus_wmi_platform_init(struct
asus_wmi *asus)
             asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
                           asus->driver->quirks->wapf,
NULL);

+    /*
+     * Check presence of Intelligent Performance
Technology (AIPT).
+     * If present store acpi handle and set
asus_aipt_present to true.
+     */
+    adev = acpi_dev_get_first_match_dev("PNP0C14",
"ATK", -1);
Is there really no way of changing the AIPT mode through
the WMI
interface?
I would prefer using the WMI interface if available, since
the
firmware might
assume that FANL is only called through the WMI interface.

Do you have a acpidump from a affected device?

Thanks,
Armin Wolf

I found a acpidump from a ASUS device with a matching FANL
method. It seems that this method
can indeed be called using the WMI interface using the DEVS()
WMI method:

[WmiMethodId(1398162756), Implemented] void DEVS([in] uint32
Device_ID, [in] uint32 Control_status, [out] uint32 result);

If Device_ID is 0x00110019, then Control_status is passed to
the FANL ACPI method.

It also seems that support for AIPT can be queried using the
DSTS() WMI method:

[WmiMethodId(1398035268), Implemented] void DSTS([in] uint32
Device_ID, [out] uint32 device_status);

Using Device_ID 0x00110019, the returned device status seems
to contain the following information:

- 16-bit current AIPT mode
- 4-bit unknown value (possible values 2, 3 and 7, maybe
number of supported modes or some kind of bitmap?)
- 1-bit with is set when (GGIV (0x0907000C) == One) is true
I just saw this conversation and i think that the behaviour
this
patch will implement in the driver was already implemented in
this patch
that got added to kernel v6.12-rc3:
https://lore.kernel.org/platform-driver-x86/20240609144849.2532-2-mohamed.ghanmi@xxxxxxxxx/

this patch introduced
ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO
0x00110019 which is the device_id that changes the fan
profiles. the
naming is not clear because it was initially intended to add
support for
fan profiles for vivobook laptops but it ended up adding
support
for a lot of modern laptops.
Nice, you are absolutely right.

So this patch series is effectively already upstream, very good.
I did some research and found out
that the status of this device id contains the following data:

Status          Supported Modes
-------------------------------
0x00[1]300[xx]  0 1 2
0x000700[xx]    0 1 2
0x000200[xx]    ??? (ODV0)
0x000700[xx]    0 1 2
0x0a0700[xx]    ??? (ODV0)

While i have no clue about the meaning of the remaining bits, i
can report that the first 8 Bits
contain the current thermal mode. Maybe adding support for this
would be nice, so the current
thermal mode can be read directly from the hardware.

I also found out that on some models the thermal mode actually
modifies the ODV0 variable which
is consumed by int3400_thermal and exposed to the Intel Thermal
Daemon. So maybe the lackluster
performance also has something to do with it.

a point that Srinivas Pandruvada mentioned about RAPL (Running
Average Power Limit)
is valid for a lot of modern vivobook and zenbook laptops but i
think
it's unrelated to fan profiles.

a lot of asus laptops that have intel cpus suffer from power
throttling.
for exemple in my case using windows, changing fan profiles
will lead to max power
changing to the values indicated in the table below (asus
vivobook 16x
pro k6604) which leads to higher performance than linux

fan Profile             power limit
-----------------------------------
Whisper                 50watts
Standard                120watts
Performance             149watts
------------------------------------

However in linux, even after changing to the appropriate fan
profile,
the power is still capped at 50watts and i found the reason why

here is the results of using the powercap-info command:

intel-rapl-mmio
     enabled: 1
     Zone 0
       name: package-0
       enabled: 1
       max_energy_range_uj: 262143328850
       Constraint 0
         name: long_term
         power_limit_uw: 30000000
         time_window_us: 55967744
         max_power_uw: 55000000
       Constraint 1
         name: short_term
         power_limit_uw: 55000000
         time_window_us: 2440
         max_power_uw: 0
intel-rapl
     enabled: 1
     Zone 0
       name: package-0
       enabled: 1
       max_energy_range_uj: 262143328850
       Constraint 0
         name: long_term
         power_limit_uw: 157000000
         time_window_us: 55967744
         max_power_uw: 55000000
       Constraint 1
         name: short_term
         power_limit_uw: 157000000
         time_window_us: 2440
         max_power_uw: 0
       Constraint 2
         name: peak_power
         power_limit_uw: 200000000
         max_power_uw: 0
       Zone 0:0
         name: core
         enabled: 0
         max_energy_range_uj: 262143328850
         Constraint 0
           name: long_term
           power_limit_uw: 0
           time_window_us: 976
       Zone 0:1
         name: uncore
         enabled: 0
         max_energy_range_uj: 262143328850
         Constraint 0
           name: long_term
           power_limit_uw: 0
           time_window_us: 976
     Zone 1
       name: psys
       enabled: 0
       max_energy_range_uj: 262143328850
       Constraint 0
         name: long_term
         power_limit_uw: 0
         time_window_us: 27983872
       Constraint 1
         name: short_term
         power_limit_uw: 0
         time_window_us: 976


as seen by the output of the command, the intel-rapl-mmio is
causing the
throttling as it sets power_limit_uw to 30 watts (readonly). so
the current fix
that i'm currently using is disabling the intel-rapl-mmio
leaving only
the intel-rapl which sets power_limit_uw to 157watts using this
command: powercap-set -p intel-rapl-mmio -z 0 -e 0

this will lead to the laptop being able to reach it's maximum
power
limit.

after doing this, when i change the platform profile through
sysfs the
laptop will start behaving as described in the table above
exactly like
windows.

in conclusion, the asus-wmi driver already has the platform
profiles
(a.k.a fan profiles)
implemented and I think that the power throttling is caused by
either
intel Power Capping Framework or asus bios.
Or the Intel Thermal Daemon somehow does not properly support
intel-rapl-mmio
or is not installed.
This was exactly it. the Intel Thermal Daemon wasn't installed. now
everything is working as expected!

Best regards,
Mohamed G.
Interesting.

Srinivas, can you verify that the Intel Thermal Daemon is installed
on the affected
Asus machines?

I begin to wonder why this thermal daemon is a userspace component,
stuff like thermal
management should use the thermal subsystem inside the kernel.
Thanks for detailed analysis here.

Here the problem is not thermal daemon or INT340x (I am author of
both).

The ODVP variable is input into thermal tables. These thermal tables
are defined by Asus via DTT tables. This results in matching certain
max and min power limits and also various temperature limits.

By default the laptop in question will boot with max limit of 17W,
which is limit for whisper mode match based on ODVP variables. There is
a SEN1 limit of 50C, once the limit reaches to 50C, you need to
throttle upto 12W as per thermal table.

If you stop thermald, yes, you will stay in 17W, so you will not see
throttle but your SEN1 (seems skin limit) limit will be violated.
Also if you remove the rapl_mmio driver, that will also work as no
means to set power limits.

Windows will do exactly same. Meeting thermal limit is a requirement.

But on Windows this ODVP variable will be set to 0 to match standard
mode. This will result in matching rules which will set the max power
to 22W and min to 17W also increase thermal limit to 55C. So
essentially lost 5W of performance.

Here WMI method as you correctly found out matching VIVO thermal
policy. But it will not set ODVP variable unless you call a WMI method
to set the mode via DEVS() on the same device ID. So although platform
power policy will say "balanced" it is actually "Whisper" for thermal
policy. On Windows when system boots the Asus service will set to
standard and will set the ODVP variable to 0 and will match the correct
table.

After Luke's help, I can do a work around from user space to change the
power policy to any other policy than balanced and then again set to
balance. This will result in setting the policy to standard via DEVS()
and also set the correct ODVP variable.

This driver on unload change the vivo thermal policy to default. But
doesn't change that to default on load time to match the default
platform power policy. So rmmod and modprobe of driver should also fix.

Thanks,
Srinivas

Good point, so basically throttle_thermal_policy_set_default() need to be called during
initialization of the thermal profile. Maybe you can send another patch which implements this?

Thanks,
Armin Wolf

Thanks,
Armin Wolf







[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux