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

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

 



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









> 
> 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