Re: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG

From: Hans de Goede
Date: Wed Jul 12 2023 - 10:58:38 EST


Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Expose various CPU and dGPU tunables that are available on many ASUS
> ROG laptops. The tunables shown in sysfs will vary depending on the CPU
> and dGPU vendor.
>
> All of these variables are write only and there is no easy way to find
> what the defaults are. In general they seem to default to the max value
> the vendor sets for the CPU and dGPU package - this is not the same as
> the min/max writable value. Values written to these variables that are
> beyond the capabilities of the CPU are ignored by the laptop.
>
> Signed-off-by: Luke D. Jones <luke@xxxxxxxxxx>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <hdegoede@xxxxxxxxxx>

(I'll fix the make htmldocs warning lkp spotted while merging this).

Regards,

Hans

> ---
> .../ABI/testing/sysfs-platform-asus-wmi | 58 ++++
> drivers/platform/x86/asus-wmi.c | 285 ++++++++++++++++++
> include/linux/platform_data/x86/asus-wmi.h | 9 +
> 3 files changed, 352 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 5624bdef49cb..caaccd28fabf 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -126,3 +126,61 @@ Description:
> Change the mini-LED mode:
> * 0 - Single-zone,
> * 1 - Multi-zone
> +
> +What: /sys/devices/platform/<platform>/ppt_pl1_spl
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
> + Shown on Intel+Nvidia or AMD+Nvidia based systems.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_pl2_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
> + on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_fppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_apu_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the APU SPPT limit. Shown on full AMD systems only.
> + * min=5, max=130
> +
> +What: /sys/devices/platform/<platform>/ppt_platform_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the platform SPPT limit. Shown on full AMD systems only.
> + * min=5, max=130
> +
> +What: /sys/devices/platform/<platform>/nv_dynamic_boost
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the dynamic boost limit of the Nvidia dGPU:
> + * min=5, max=25
> +
> +What: /sys/devices/platform/<platform>/nv_temp_target
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <luke@xxxxxxxxxx>
> +Description:
> + Set the target temperature limit of the Nvidia dGPU:
> + * min=75, max=87
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 1fc9e8afc2f3..d9a353081f91 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -117,6 +117,16 @@ module_param(fnlock_default, bool, 0444);
> /* Mask to determine if setting temperature or percentage */
> #define FAN_CURVE_PWM_MASK 0x04
>
> +/* Limits for tunables available on ASUS ROG laptops */
> +#define PPT_TOTAL_MIN 5
> +#define PPT_TOTAL_MAX 250
> +#define PPT_CPU_MIN 5
> +#define PPT_CPU_MAX 130
> +#define NVIDIA_BOOST_MIN 5
> +#define NVIDIA_BOOST_MAX 25
> +#define NVIDIA_TEMP_MIN 75
> +#define NVIDIA_TEMP_MAX 87
> +
> static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
>
> static int throttle_thermal_policy_write(struct asus_wmi *);
> @@ -247,6 +257,15 @@ struct asus_wmi {
> bool dgpu_disable_available;
> bool gpu_mux_mode_available;
>
> + /* Tunables provided by ASUS for gaming laptops */
> + bool ppt_pl2_sppt_available;
> + bool ppt_pl1_spl_available;
> + bool ppt_apu_sppt_available;
> + bool ppt_plat_sppt_available;
> + bool ppt_fppt_available;
> + bool nv_dyn_boost_available;
> + bool nv_temp_tgt_available;
> +
> bool kbd_rgb_mode_available;
> bool kbd_rgb_state_available;
>
> @@ -946,6 +965,244 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
> NULL,
> };
>
> +/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> +static ssize_t ppt_pl2_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_pl2_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_pl2_sppt);
> +
> +/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/
> +static ssize_t ppt_pl1_spl_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_pl1_spl: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_pl1_spl);
> +
> +/* Tunable: PPT APU FPPT ******************************************************/
> +static ssize_t ppt_fppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_fppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_fppt);
> +
> +/* Tunable: PPT APU SPPT *****************************************************/
> +static ssize_t ppt_apu_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_apu_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_apu_sppt);
> +
> +/* Tunable: PPT platform SPPT ************************************************/
> +static ssize_t ppt_platform_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_platform_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_platform_sppt);
> +
> +/* Tunable: NVIDIA dynamic boost *********************************************/
> +static ssize_t nv_dynamic_boost_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result);
> + if (err) {
> + pr_warn("Failed to set nv_dynamic_boost: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(nv_dynamic_boost);
> +
> +/* Tunable: NVIDIA temperature target ****************************************/
> +static ssize_t nv_temp_target_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result);
> + if (err) {
> + pr_warn("Failed to set nv_temp_target: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(nv_temp_target);
> +
> /* Battery ********************************************************************/
>
> /* The battery maximum charging percentage */
> @@ -3775,6 +4032,13 @@ static struct attribute *platform_attributes[] = {
> &dev_attr_als_enable.attr,
> &dev_attr_fan_boost_mode.attr,
> &dev_attr_throttle_thermal_policy.attr,
> + &dev_attr_ppt_pl2_sppt.attr,
> + &dev_attr_ppt_pl1_spl.attr,
> + &dev_attr_ppt_fppt.attr,
> + &dev_attr_ppt_apu_sppt.attr,
> + &dev_attr_ppt_platform_sppt.attr,
> + &dev_attr_nv_dynamic_boost.attr,
> + &dev_attr_nv_temp_target.attr,
> &dev_attr_panel_od.attr,
> &dev_attr_mini_led_mode.attr,
> NULL
> @@ -3812,6 +4076,20 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> ok = asus->fan_boost_mode_available;
> else if (attr == &dev_attr_throttle_thermal_policy.attr)
> ok = asus->throttle_thermal_policy_available;
> + else if (attr == &dev_attr_ppt_pl2_sppt.attr)
> + ok = asus->ppt_pl2_sppt_available;
> + else if (attr == &dev_attr_ppt_pl1_spl.attr)
> + ok = asus->ppt_pl1_spl_available;
> + else if (attr == &dev_attr_ppt_fppt.attr)
> + ok = asus->ppt_fppt_available;
> + else if (attr == &dev_attr_ppt_apu_sppt.attr)
> + ok = asus->ppt_apu_sppt_available;
> + else if (attr == &dev_attr_ppt_platform_sppt.attr)
> + ok = asus->ppt_plat_sppt_available;
> + else if (attr == &dev_attr_nv_dynamic_boost.attr)
> + ok = asus->nv_dyn_boost_available;
> + else if (attr == &dev_attr_nv_temp_target.attr)
> + ok = asus->nv_temp_tgt_available;
> else if (attr == &dev_attr_panel_od.attr)
> ok = asus->panel_overdrive_available;
> else if (attr == &dev_attr_mini_led_mode.attr)
> @@ -4077,6 +4355,13 @@ static int asus_wmi_add(struct platform_device *pdev)
> asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
> asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
> asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
> + asus->ppt_pl2_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL2_SPPT);
> + asus->ppt_pl1_spl_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL1_SPL);
> + asus->ppt_fppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_FPPT);
> + asus->ppt_apu_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_APU_SPPT);
> + asus->ppt_plat_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PLAT_SPPT);
> + asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST);
> + asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
> asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
> asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
>
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index ea80361ac6c7..16e99a1c37fc 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -86,6 +86,15 @@
> #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
> #define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032
>
> +/* Tunables for AUS ROG laptops */
> +#define ASUS_WMI_DEVID_PPT_PL2_SPPT 0x001200A0
> +#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3
> +#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0
> +#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1
> +#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1
> +#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0
> +#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2
> +
> /* Power */
> #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
>