From nobody Sat Jun 13 03:29:22 2026 Received: from mail-10626.protonmail.ch (mail-10626.protonmail.ch [79.135.106.26]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2586747A0D8 for ; Wed, 13 May 2026 15:47:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.26 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778687273; cv=none; b=W2jglnTaaAJ+EFN52Xm/qRgCvygVfKYREiVXquK2eOUAEwY4pe8Lx+q26/zB+amPC3o/DyudTKNaUEHdrHsowVm0NtZNk2+H2RsHx/qXC9b/kt6P3PBB7BBM62q+0iJsTbK5eTXvwEk3sC2JNCw6qkyfZyr/scYcftgJtwgaPsM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778687273; c=relaxed/simple; bh=JW806Mza6/CGzprvTIZwHv4oY2J8KIsQUYgVYzwFzJs=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=DSNmp1OTSOMUh6ZuyQsflB2EK+gCtY9WbZ4ES4snY8Xn959YI+/ppwxCavxhe2hRbJcGJcqkzO9xcSzL2dPLvCIK2hf8mNEdg3aOTkL/j7r5sGBacdUm2w55E51GEmah7oZJluJ2XfzWuU32kRZZVLUN//BtQCidQ+bs+YHyae8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev; spf=pass smtp.mailfrom=ghoul.dev; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b=s4KYwpTp; arc=none smtp.client-ip=79.135.106.26 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b="s4KYwpTp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ghoul.dev; s=protonmail; t=1778687260; x=1778946460; bh=6vidsa8RmgfNvZCWuhwkcXTsNAc0VFs/m9IdhIXPQhk=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=s4KYwpTphz0g86lZBiRvtVQAe5iXJUoHbcW/Bc68qAtdAn8iz+Bm2xHM2kY+oxfb2 LBa8Mqz1o5OCO2hJyJWwY6QfIAjXMsXkg774gtM22BdUZEAx4MwlJPJ2J0p8kgcxeP c/LesRhpHccU6YbGSp02v5ch51srLf42IgWry4SYEZP88Pvjcp8n7BgpMEYH1yqn1e 1Azgk42VqNk6V8M2tQNyUrKwuFHOZaHLKemQxn6gAsiwSiNADJzTktux/ngH+hoCmn r7gIyxAYRjfRdV/2T1+5D+AUh3mU+ylwLPENWNNceq0PfSIRDbElwL2UMalRN0rRzl eiGhDysSCTaAQ== Date: Wed, 13 May 2026 15:47:33 +0000 To: platform-driver-x86@vger.kernel.org From: Ahmed Yaseen Cc: yaseen@ghoul.dev, corentin.chary@gmail.com, luke@ljones.dev, denis.benato@linux.dev, derekjohn.clark@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, prasanth.ksr@dell.com, mpearson-lenovo@squebb.ca, Dell.Client.Kernel@dell.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] platform/x86: asus-armoury: gate PPT writes behind active fan curve Message-ID: <20260513154714.25160-2-yaseen@ghoul.dev> In-Reply-To: <20260511061901.907540-1-yaseen@ghoul.dev> References: <20260511061901.907540-1-yaseen@ghoul.dev> Feedback-ID: 177610485:user:proton X-Pm-Message-ID: 195c003e991b27a121709d9a8b76b890bff10f70 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On models flagged with requires_fan_curve in the DMI power_data table (28 entries), the BIOS ACPI method SPLX only writes PPT values to the EC when the fan mode is set to Manual (FANM=3D4). FANM is set to 4 by the DEFC method when a custom fan curve is written. Without an active custom fan curve, the WMI DEVS call returns success but the firmware silently ignores the PPT value, so userspace observes no effect from its write. Gate writes to ASUS_WMI_DEVID_PPT_{PL1_SPL,PL2_SPPT,PL3_FPPT,APU_SPPT, PLAT_SPPT} on a check of asus_wmi_custom_fan_curve_is_enabled(), and return -EBUSY with a pr_warn() when no fan curve is active on an affected model. Export the helper from asus-wmi so asus-armoury can call it across module boundaries. Signed-off-by: Ahmed Yaseen --- drivers/platform/x86/asus-armoury.c | 20 ++++++++++++++++ drivers/platform/x86/asus-wmi.c | 28 ++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 5 ++++ 3 files changed, 53 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asu= s-armoury.c index 5b0987ccc270..9b1c41a25b38 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -93,6 +93,8 @@ struct asus_armoury_priv { =20 u32 mini_led_dev_id; u32 gpu_mux_dev_id; + + bool requires_fan_curve; }; =20 static struct asus_armoury_priv asus_armoury =3D { @@ -216,6 +218,22 @@ static int armoury_set_devstate(struct kobj_attribute = *attr, u32 result; int err; =20 + /* On some models, PPT changes require an active fan curve */ + if (asus_armoury.requires_fan_curve) { + switch (dev_id) { + case ASUS_WMI_DEVID_PPT_PL1_SPL: + case ASUS_WMI_DEVID_PPT_PL2_SPPT: + case ASUS_WMI_DEVID_PPT_PL3_FPPT: + case ASUS_WMI_DEVID_PPT_APU_SPPT: + case ASUS_WMI_DEVID_PPT_PLAT_SPPT: + if (!asus_wmi_custom_fan_curve_is_enabled()) { + pr_warn("PPT change requires an active fan curve on this model. Enable= a custom fan curve first.\n"); + return -EBUSY; + } + break; + } + } + /* * Prevent developers from bricking devices or issuing dangerous * commands that can be difficult or impossible to recover from. @@ -1002,6 +1020,8 @@ static void init_rog_tunables(void) return; } =20 + asus_armoury.requires_fan_curve =3D power_data->requires_fan_curve; + /* Initialize AC power tunables */ ac_limits =3D power_data->ac_data; if (ac_limits) { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wm= i.c index 80144c412b90..b05218d31d90 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -341,6 +341,9 @@ struct asus_wmi { /* Global to allow setting externally without requiring driver data */ static enum asus_ally_mcu_hack use_ally_mcu_hack =3D ASUS_WMI_ALLY_MCU_HAC= K_INIT; =20 +/* Global asus_wmi instance for use by exported functions */ +static struct asus_wmi *asus_wmi_instance; + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static void asus_wmi_show_deprecated(void) { @@ -4001,6 +4004,28 @@ static int asus_wmi_custom_fan_curve_init(struct asu= s_wmi *asus) return 0; } =20 +/* + * Returns true if at least one custom fan curve is active + * + * Used by asus-armoury to check if PPT writes will be accepted by the BIOS + * on models that require an active fan curve for TDP changes. + */ +bool asus_wmi_custom_fan_curve_is_enabled(void) +{ + struct asus_wmi *asus =3D asus_wmi_instance; + struct fan_curve_data *curves; + + if (!asus) + return false; + + curves =3D asus->custom_fan_curves; + + return (asus->cpu_fan_curve_available && curves[FAN_CURVE_DEV_CPU].enable= d) || + (asus->gpu_fan_curve_available && curves[FAN_CURVE_DEV_GPU].enable= d) || + (asus->mid_fan_curve_available && curves[FAN_CURVE_DEV_MID].enable= d); +} +EXPORT_SYMBOL_NS_GPL(asus_wmi_custom_fan_curve_is_enabled, "ASUS_WMI"); + /* Throttle thermal policy ***********************************************= *****/ static int throttle_thermal_policy_write(struct asus_wmi *asus) { @@ -5156,6 +5181,8 @@ static int asus_wmi_add(struct platform_device *pdev) =20 asus_wmi_debugfs_init(asus); =20 + asus_wmi_instance =3D asus; + return 0; =20 fail_wmi_handler: @@ -5199,6 +5226,7 @@ static void asus_wmi_remove(struct platform_device *d= evice) throttle_thermal_policy_set_default(asus); asus_wmi_battery_exit(asus); =20 + asus_wmi_instance =3D NULL; kfree(asus); } =20 diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/pla= tform_data/x86/asus-wmi.h index 554f41b827e1..5d57293ced6c 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -196,6 +196,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u= 32 arg1, u32 *retval); int asus_hid_register_listener(struct asus_hid_listener *cdev); void asus_hid_unregister_listener(struct asus_hid_listener *cdev); int asus_hid_event(enum asus_hid_event event); +bool asus_wmi_custom_fan_curve_is_enabled(void); #else static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) { @@ -227,6 +228,10 @@ static inline int asus_hid_event(enum asus_hid_event e= vent) { return -ENODEV; } +static inline bool asus_wmi_custom_fan_curve_is_enabled(void) +{ + return false; +} #endif =20 #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ --=20 2.54.0 From nobody Sat Jun 13 03:29:22 2026 Received: from mail-4318.protonmail.ch (mail-4318.protonmail.ch [185.70.43.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 137652D0C82; Mon, 11 May 2026 06:19:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.43.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778480379; cv=none; b=UG4Q6QfiBBXLQXhaEHPazZoO0S1v7ffIusc0hj4JnaT02k5dVph3Vbfya6ApY60dpGAlgrUe4LGgYoSjI8Uds99/Bq7Qy6CVn1Gi1w+TVFgg9P+pUPouOVjVAxkmBoW6YFYJW0JFcKWu8qbwft091Ge1yqUW9XYvG4NHVc6wEqo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778480379; c=relaxed/simple; bh=VHI32ivS4lcoHkIngKwvFOH/SsYCT3zaxv7zHEQyAIg=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=MkvT059lyU2N7AOI4SS/iZo0HOcciM/Mm2tfl7ZUDrKxSvcixvVnF9Z2uThvlNWiW6nRYZt87OqtGCn0CBwW4p1BQI2GH6XJO5kTgmgXByo9yvuaklaWbfeVdXr2z+SsqSS6kHvb+igqTaQ6yJuZ0F25lPtomV6pvb/QKZ4X1Bs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev; spf=pass smtp.mailfrom=ghoul.dev; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b=KrbA8ozc; arc=none smtp.client-ip=185.70.43.18 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b="KrbA8ozc" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ghoul.dev; s=protonmail; t=1778480374; x=1778739574; bh=con8/ExgSJJrwRAmc8de7GekzLWWxkj4P7o+8w2/vpA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=KrbA8ozcyIcWET+GE8uqedMHhkfZ0FrznVgLb+lW1c4j0gIYWyxCKAPdqpeDXQbbM gShx50P7nDSA6+9Jp9FuKPNc9ixUcH7bP6sgv7EoVgEDBgFpi7OE3EVIR8Uq2DBKxJ 5VnBOACzHZGU8waDNtA5IEn9UmBb/VEq8Gq0FJDxv798XgkAtkAY1rprDO/s3fHip7 90x2qRNRcc/zp5Ak2OvthiVvxza15yjWRvGJOTlNTNG5cPFZPGBigi2hZHb6ge8nNt RY0AjtJsQeG7Tv2ebptRd/PEXuffJGNqeOcnhd8Mc34yFcDWfvEFWdsYiqoo/darjc /a9VI6gtc6Fgg== Date: Mon, 11 May 2026 06:19:30 +0000 To: platform-driver-x86@vger.kernel.org From: Ahmed Yaseen Cc: yaseen@ghoul.dev, corentin.chary@gmail.com, luke@ljones.dev, denis.benato@linux.dev, derekjohn.clark@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, prasanth.ksr@dell.com, mpearson-lenovo@squebb.ca, Dell.Client.Kernel@dell.com, linux-kernel@vger.kernel.org, asus-linux@lists.linux.dev Subject: [PATCH 1/2] platform/x86: asus-armoury: gate PPT writes behind active fan curve Message-ID: <20260511061901.907540-2-yaseen@ghoul.dev> In-Reply-To: <20260511061901.907540-1-yaseen@ghoul.dev> References: <20260511061901.907540-1-yaseen@ghoul.dev> Feedback-ID: 177610485:user:proton X-Pm-Message-ID: 18d5944a2db392747f3f6f785ccf59ca0db2aa0c Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" On models flagged with requires_fan_curve in the DMI power_data table (28 entries), the BIOS ACPI method SPLX only writes PPT values to the EC when the fan mode is set to Manual (FANM=3D4). FANM is set to 4 by the DEFC method when a custom fan curve is written. Without an active custom fan curve, the WMI DEVS call returns success but the firmware silently ignores the PPT value, so userspace observes no effect from its write. Gate writes to ASUS_WMI_DEVID_PPT_{PL1_SPL,PL2_SPPT,PL3_FPPT,APU_SPPT, PLAT_SPPT} on a check of asus_wmi_custom_fan_curve_is_enabled(), and return -ENODEV with a pr_warn() when no fan curve is active on an affected model. Export the helper from asus-wmi so asus-armoury can call it across module boundaries. Signed-off-by: Ahmed Yaseen --- drivers/platform/x86/asus-armoury.c | 20 ++++++++++++++++ drivers/platform/x86/asus-wmi.c | 28 ++++++++++++++++++++++ include/linux/platform_data/x86/asus-wmi.h | 5 ++++ 3 files changed, 53 insertions(+) diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asu= s-armoury.c index 5b0987ccc270..01e552573674 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -93,6 +93,8 @@ struct asus_armoury_priv { =20 u32 mini_led_dev_id; u32 gpu_mux_dev_id; + + bool requires_fan_curve; }; =20 static struct asus_armoury_priv asus_armoury =3D { @@ -216,6 +218,22 @@ static int armoury_set_devstate(struct kobj_attribute = *attr, u32 result; int err; =20 + /* On some models, PPT changes require an active fan curve */ + if (asus_armoury.requires_fan_curve) { + switch (dev_id) { + case ASUS_WMI_DEVID_PPT_PL1_SPL: + case ASUS_WMI_DEVID_PPT_PL2_SPPT: + case ASUS_WMI_DEVID_PPT_PL3_FPPT: + case ASUS_WMI_DEVID_PPT_APU_SPPT: + case ASUS_WMI_DEVID_PPT_PLAT_SPPT: + if (!asus_wmi_custom_fan_curve_is_enabled()) { + pr_warn("PPT change requires an active fan curve on this model. Enable= a custom fan curve first.\n"); + return -ENODEV; + } + break; + } + } + /* * Prevent developers from bricking devices or issuing dangerous * commands that can be difficult or impossible to recover from. @@ -1002,6 +1020,8 @@ static void init_rog_tunables(void) return; } =20 + asus_armoury.requires_fan_curve =3D power_data->requires_fan_curve; + /* Initialize AC power tunables */ ac_limits =3D power_data->ac_data; if (ac_limits) { diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wm= i.c index 80144c412b90..b05218d31d90 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -341,6 +341,9 @@ struct asus_wmi { /* Global to allow setting externally without requiring driver data */ static enum asus_ally_mcu_hack use_ally_mcu_hack =3D ASUS_WMI_ALLY_MCU_HAC= K_INIT; =20 +/* Global asus_wmi instance for use by exported functions */ +static struct asus_wmi *asus_wmi_instance; + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS) static void asus_wmi_show_deprecated(void) { @@ -4001,6 +4004,28 @@ static int asus_wmi_custom_fan_curve_init(struct asu= s_wmi *asus) return 0; } =20 +/* + * Returns true if at least one custom fan curve is active + * + * Used by asus-armoury to check if PPT writes will be accepted by the BIOS + * on models that require an active fan curve for TDP changes. + */ +bool asus_wmi_custom_fan_curve_is_enabled(void) +{ + struct asus_wmi *asus =3D asus_wmi_instance; + struct fan_curve_data *curves; + + if (!asus) + return false; + + curves =3D asus->custom_fan_curves; + + return (asus->cpu_fan_curve_available && curves[FAN_CURVE_DEV_CPU].enable= d) || + (asus->gpu_fan_curve_available && curves[FAN_CURVE_DEV_GPU].enable= d) || + (asus->mid_fan_curve_available && curves[FAN_CURVE_DEV_MID].enable= d); +} +EXPORT_SYMBOL_NS_GPL(asus_wmi_custom_fan_curve_is_enabled, "ASUS_WMI"); + /* Throttle thermal policy ***********************************************= *****/ static int throttle_thermal_policy_write(struct asus_wmi *asus) { @@ -5156,6 +5181,8 @@ static int asus_wmi_add(struct platform_device *pdev) =20 asus_wmi_debugfs_init(asus); =20 + asus_wmi_instance =3D asus; + return 0; =20 fail_wmi_handler: @@ -5199,6 +5226,7 @@ static void asus_wmi_remove(struct platform_device *d= evice) throttle_thermal_policy_set_default(asus); asus_wmi_battery_exit(asus); =20 + asus_wmi_instance =3D NULL; kfree(asus); } =20 diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/pla= tform_data/x86/asus-wmi.h index 554f41b827e1..5d57293ced6c 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -196,6 +196,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u= 32 arg1, u32 *retval); int asus_hid_register_listener(struct asus_hid_listener *cdev); void asus_hid_unregister_listener(struct asus_hid_listener *cdev); int asus_hid_event(enum asus_hid_event event); +bool asus_wmi_custom_fan_curve_is_enabled(void); #else static inline void set_ally_mcu_hack(enum asus_ally_mcu_hack status) { @@ -227,6 +228,10 @@ static inline int asus_hid_event(enum asus_hid_event e= vent) { return -ENODEV; } +static inline bool asus_wmi_custom_fan_curve_is_enabled(void) +{ + return false; +} #endif =20 #endif /* __PLATFORM_DATA_X86_ASUS_WMI_H */ --=20 2.54.0 From nobody Sat Jun 13 03:29:22 2026 Received: from mail-06.mail-europe.com (mail-06.mail-europe.com [85.9.210.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1DA1647AF42; Wed, 13 May 2026 15:47:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=85.9.210.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778687281; cv=none; b=aX/kUcUALqwwlIgyrVik3LiZ+fvPua3cG12zs7fIe01D84MLa0pmrxI/BPfIpK/fB0C490LF9jILQt+6dphpzcfX6jR4G7g1Ifjsujh3L14DpDDXHXuG3Q/bAWFBXRT7km7zDzfjHR+NouBICkrwOR50lqg2O1t0jeRv8tvozgE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778687281; c=relaxed/simple; bh=0Z3O/+iBjwk25Sjwj2+UlIX9lnQi9fTRWmCz9pkq6yE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=r8ZdZnhCtiHRwnu0VbIgKeQVkXFaust5Fm56Qf3+YDXZnXD6/E0HXM1rkBGcuRzybbGg17ZUaevqfh+rvqtN+5PFztsFbiQKRwrnDbCkWseR5FMFPZnbjLtKyKCQBKcuMxPyf3rg764MNJMDd9pNQfie6yjvgxixyw96JLP5HDo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev; spf=pass smtp.mailfrom=ghoul.dev; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b=dVLpHp3a; arc=none smtp.client-ip=85.9.210.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b="dVLpHp3a" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ghoul.dev; s=protonmail; t=1778687271; x=1778946471; bh=Qa/XDdTieujjNbBnzvDVqeoZ6K3OneNDmc+5p2ujssM=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=dVLpHp3aFOFpiFgQWDnVTTSXHe3jOSQq48TpEmQH6xCJwAzSV7wZIEzXr/JtS2vU5 pbGXv1Zwe3iSrUOTcONF/Uq2H4zzVQyitvpaYPxrevEJ0JlqSKDwWowwEK4mVsUENd 4aXKWyU5Jxh6REa6WCxcKL1FV6n9+mzZzrC8sGbnhi3j40ziouzmjAmw78preeU/rq PuAFz86jPr5NRwc1BUlmQnCdqnfOKOb/IPiR+gPulCjrGaTJF6iwR1DYR4yL4ZrNf+ S0lrxKHkkmynTHYj1XpI2y2vs70EM+8v1yQfVcYDctq8SI5RssOCzkJhxHQlm+pscr 96SCQ6q+QoeRw== Date: Wed, 13 May 2026 15:47:44 +0000 To: platform-driver-x86@vger.kernel.org From: Ahmed Yaseen Cc: yaseen@ghoul.dev, corentin.chary@gmail.com, luke@ljones.dev, denis.benato@linux.dev, derekjohn.clark@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, prasanth.ksr@dell.com, mpearson-lenovo@squebb.ca, Dell.Client.Kernel@dell.com, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] platform/x86: asus-armoury: expose requires_fan_curve via sysfs Message-ID: <20260513154714.25160-3-yaseen@ghoul.dev> In-Reply-To: <20260511061901.907540-1-yaseen@ghoul.dev> References: <20260511061901.907540-1-yaseen@ghoul.dev> Feedback-ID: 177610485:user:proton X-Pm-Message-ID: 8693c17f77e42fc502e232992efc58f85045093a Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Expose the per-model requires_fan_curve flag as a read-only sysfs attribute so userspace tools (asusctl, rogcc) can discover whether the system requires an active custom fan curve for PPT changes to take effect, and warn the user before issuing such writes. The attribute appears at: /sys/class/firmware-attributes/asus-armoury/attributes/requires_fan_curve Document the attribute in Documentation/ABI/testing/sysfs-class-firmware-attributes. Signed-off-by: Ahmed Yaseen --- .../testing/sysfs-class-firmware-attributes | 25 +++++++++++++++++++ drivers/platform/x86/asus-armoury.c | 15 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Do= cumentation/ABI/testing/sysfs-class-firmware-attributes index 2713efa509b4..12700a077f43 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -492,3 +492,28 @@ Description: log entry size identifies audit log size for the current BIOS version. The current size is 16 bytes but it can be up to 128 bytes long in futur= e BIOS versions. + +What: /sys/class/firmware-attributes/asus-armoury/attributes/requires_fan= _curve +Date: May 2026 +KernelVersion: 7.1 +Contact: platform-driver-x86@vger.kernel.org +Description: + A read-only attribute that reads 1 on ASUS ROG models where the + BIOS requires a custom fan curve to be active before Package + Power Tracking (PPT) writes take effect. On affected models, the + BIOS silently ignores writes to ppt_pl1_spl, ppt_pl2_sppt, + ppt_pl3_fppt, ppt_apu_sppt and ppt_platform_sppt unless a custom + fan curve has been written via the asus_custom_fan_curve hwmon + device. + + The kernel rejects PPT writes with -EBUSY on these models when + no fan curve is active. Userspace tools can read this attribute + to surface a clear prerequisite to the user instead of letting + the write appear to succeed at the firmware-attribute layer + while the BIOS discards it. + + =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + 0 No fan curve prerequisite for PPT writes. + 1 A custom fan curve must be active; PPT writes + return -EBUSY otherwise. + =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asu= s-armoury.c index 9b1c41a25b38..9b483d7e9855 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -127,6 +127,13 @@ static ssize_t pending_reboot_show(struct kobject *kob= j, struct kobj_attribute * =20 static struct kobj_attribute pending_reboot =3D __ATTR_RO(pending_reboot); =20 +static ssize_t requires_fan_curve_show(struct kobject *kobj, struct kobj_a= ttribute *attr, char *buf) +{ + return sysfs_emit(buf, "%d\n", asus_armoury.requires_fan_curve); +} + +static struct kobj_attribute requires_fan_curve =3D __ATTR_RO(requires_fan= _curve); + static bool asus_bios_requires_reboot(struct kobj_attribute *attr) { return !strcmp(attr->attr.name, "gpu_mux_mode") || @@ -914,6 +921,12 @@ static int asus_fw_attr_add(void) goto err_destroy_kset; } =20 + err =3D sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan= _curve.attr); + if (err) { + pr_err("Failed to create requires_fan_curve attribute\n"); + goto err_destroy_kset; + } + asus_armoury.mini_led_dev_id =3D 0; if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) asus_armoury.mini_led_dev_id =3D ASUS_WMI_DEVID_MINI_LED_MODE; @@ -987,6 +1000,7 @@ static int asus_fw_attr_add(void) if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr= _group); err_remove_file: + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan_curve.a= ttr); sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); err_destroy_kset: kset_unregister(asus_armoury.fw_attr_kset); @@ -1161,6 +1175,7 @@ static void __exit asus_fw_exit(void) if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr= _group); =20 + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan_curve.a= ttr); sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); kset_unregister(asus_armoury.fw_attr_kset); device_destroy(&firmware_attributes_class, MKDEV(0, 0)); --=20 2.54.0 From nobody Sat Jun 13 03:29:22 2026 Received: from mail-10624.protonmail.ch (mail-10624.protonmail.ch [79.135.106.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 383192D060D; Mon, 11 May 2026 06:19:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.24 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778480399; cv=none; b=dAUm0Ct2bJOzfcyWpQIz6ANyod8ddtinqS0EOL/0WxtRz5kYwX7CWGGttBshBPjoIlD0/feQWbYyy7gHbBvgLyFOI0S6M3qHM4myljNQGt1fGZHnm/IOd4nik9tnnLyS4WB8NFwFsTPKVGDCueB0xODhYiaqYGfD0d5F4sapH6s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1778480399; c=relaxed/simple; bh=F7Zy+/+r1u+FBNXhEbWkPG9UHD1VB+ZC4Six7ySIj+M=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hUmZMZ5+Nx0Z2vBsk2q6jLj34fVdpAhFRm4c48JW6/uEoXthWVqKlmQ5KOcQckbdEyCy2+fgEsamQVoiMJe6tYfrJd9aw2lviSVrKRgAnUSPl59Xk94opEGz3sWvur72FQrI7cNBSFpghvcx/TMd5jacU0xeilvDRTtzO86aZTw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev; spf=pass smtp.mailfrom=ghoul.dev; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b=TX/Vydre; arc=none smtp.client-ip=79.135.106.24 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=ghoul.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ghoul.dev header.i=@ghoul.dev header.b="TX/Vydre" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ghoul.dev; s=protonmail; t=1778480390; x=1778739590; bh=yWVmqaTEFuJVys4izhrdwM3qdlLDYgmQeOXyZ30TySw=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=TX/VydreRJh6/WlNQivX6Q33R+W1jBbQNMMiD17cJoMdKNYN1mkcsXQrgJ92kva7P 6HBAPrnBzLUXPZ7Rofo8m6xbjJaYYod4uLrUBN6eGCbmZrgtSP1wkbJ33aJocRgDLl zhoF54IPCy8EkMkmqas3819kfi5FWKbqsBwu7f1uJd5frffMx2RoWuZkp1GZ2L73Io ae+lkk+f5iPCjDnGV/mO0PA0ecFSwniXQBrlHTSaiJvYCiduiAO/BeI7LLBQDD2OqT oXNtACUWecUgYJ5nEBO8DhToe0egWzLwUO3no3QfqB2IhlR55je54mKa2ZaZOEEBUQ XKNep3sLm0ucw== Date: Mon, 11 May 2026 06:19:43 +0000 To: platform-driver-x86@vger.kernel.org From: Ahmed Yaseen Cc: yaseen@ghoul.dev, corentin.chary@gmail.com, luke@ljones.dev, denis.benato@linux.dev, derekjohn.clark@gmail.com, hansg@kernel.org, ilpo.jarvinen@linux.intel.com, prasanth.ksr@dell.com, mpearson-lenovo@squebb.ca, Dell.Client.Kernel@dell.com, linux-kernel@vger.kernel.org, asus-linux@lists.linux.dev Subject: [PATCH 2/2] platform/x86: asus-armoury: expose requires_fan_curve via sysfs Message-ID: <20260511061901.907540-3-yaseen@ghoul.dev> In-Reply-To: <20260511061901.907540-1-yaseen@ghoul.dev> References: <20260511061901.907540-1-yaseen@ghoul.dev> Feedback-ID: 177610485:user:proton X-Pm-Message-ID: 8c2c7762b075861358c3a08902a943f8f891bde5 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Expose the per-model requires_fan_curve flag as a read-only sysfs attribute so userspace tools (asusctl, rogcc) can discover whether the system requires an active custom fan curve for PPT changes to take effect, and warn the user before issuing such writes. The attribute appears at: /sys/class/firmware-attributes/asus-armoury/attributes/requires_fan_curve Document the attribute in Documentation/ABI/testing/sysfs-class-firmware-attributes. Signed-off-by: Ahmed Yaseen --- .../testing/sysfs-class-firmware-attributes | 25 +++++++++++++++++++ drivers/platform/x86/asus-armoury.c | 15 +++++++++++ 2 files changed, 40 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-firmware-attributes b/Do= cumentation/ABI/testing/sysfs-class-firmware-attributes index 2713efa509b4..cff90c5840db 100644 --- a/Documentation/ABI/testing/sysfs-class-firmware-attributes +++ b/Documentation/ABI/testing/sysfs-class-firmware-attributes @@ -492,3 +492,28 @@ Description: log entry size identifies audit log size for the current BIOS version. The current size is 16 bytes but it can be up to 128 bytes long in futur= e BIOS versions. + +What: /sys/class/firmware-attributes/asus-armoury/attributes/requires_fan= _curve +Date: May 2026 +KernelVersion: 7.1 +Contact: platform-driver-x86@vger.kernel.org +Description: + A read-only attribute that reads 1 on ASUS ROG models where the + BIOS requires a custom fan curve to be active before Package + Power Tracking (PPT) writes take effect. On affected models, the + BIOS silently ignores writes to ppt_pl1_spl, ppt_pl2_sppt, + ppt_pl3_fppt, ppt_apu_sppt and ppt_platform_sppt unless a custom + fan curve has been written via the asus_custom_fan_curve hwmon + device. + + The kernel rejects PPT writes with -ENODEV on these models when + no fan curve is active. Userspace tools can read this attribute + to surface a clear prerequisite to the user instead of letting + the write appear to succeed at the firmware-attribute layer + while the BIOS discards it. + + =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + 0 No fan curve prerequisite for PPT writes. + 1 A custom fan curve must be active; PPT writes + return -ENODEV otherwise. + =3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asu= s-armoury.c index 01e552573674..fde6167c7f4e 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -127,6 +127,13 @@ static ssize_t pending_reboot_show(struct kobject *kob= j, struct kobj_attribute * =20 static struct kobj_attribute pending_reboot =3D __ATTR_RO(pending_reboot); =20 +static ssize_t requires_fan_curve_show(struct kobject *kobj, struct kobj_a= ttribute *attr, char *buf) +{ + return sysfs_emit(buf, "%d\n", asus_armoury.requires_fan_curve); +} + +static struct kobj_attribute requires_fan_curve =3D __ATTR_RO(requires_fan= _curve); + static bool asus_bios_requires_reboot(struct kobj_attribute *attr) { return !strcmp(attr->attr.name, "gpu_mux_mode") || @@ -914,6 +921,12 @@ static int asus_fw_attr_add(void) goto err_destroy_kset; } =20 + err =3D sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan= _curve.attr); + if (err) { + pr_err("Failed to create requires_fan_curve attribute\n"); + goto err_destroy_kset; + } + asus_armoury.mini_led_dev_id =3D 0; if (armoury_has_devstate(ASUS_WMI_DEVID_MINI_LED_MODE)) asus_armoury.mini_led_dev_id =3D ASUS_WMI_DEVID_MINI_LED_MODE; @@ -987,6 +1000,7 @@ static int asus_fw_attr_add(void) if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr= _group); err_remove_file: + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan_curve.a= ttr); sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); err_destroy_kset: kset_unregister(asus_armoury.fw_attr_kset); @@ -1161,6 +1175,7 @@ static void __exit asus_fw_exit(void) if (asus_armoury.mini_led_dev_id) sysfs_remove_group(&asus_armoury.fw_attr_kset->kobj, &mini_led_mode_attr= _group); =20 + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &requires_fan_curve.a= ttr); sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); kset_unregister(asus_armoury.fw_attr_kset); device_destroy(&firmware_attributes_class, MKDEV(0, 0)); --=20 2.54.0