[PATCH] platform/x86: asus-wmi: validate custom fan curves on enable

From: Ahmed Yaseen

Date: Fri Aug 28 2026 - 12:08:19 EST


Custom fan curves reach firmware unchecked, so a curve whose temperature
or PWM decreases from one point to the next is accepted. The firmware
does not respect such a curve: a first point of 100% followed by 50%
leaves every point running at 100%. The kernel keeps reporting the
points that were written, so sysfs stops describing what the fans are
actually doing.

Reject the curve when it is enabled. Validate on enable rather than on
write because fan curves are written one point at a time and are
inconsistent mid-write.

Fixes: 0f0ac158d28f ("platform/x86: asus-wmi: Add support for custom fan curves")
Reported-by: Nir Yehoshua <nir@xxxxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Ahmed Yaseen <yaseen@xxxxxxxxx>
---
drivers/platform/x86/asus-wmi.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index a65090429ca7..3b743fec5c64 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -3714,6 +3714,33 @@ static int fan_curve_write(struct asus_wmi *asus,
arg1, arg2, arg3, arg4, &ret);
}

+/*
+ * A fan curve is a set of points the firmware interpolates between, so it
+ * only makes sense if neither temperature nor PWM ever decreases along it.
+ */
+static int fan_curve_validate(struct device *dev, struct fan_curve_data *data)
+{
+ u8 *percents = data->percents;
+ u8 *temps = data->temps;
+ int i;
+
+ for (i = 1; i < FAN_CURVE_POINTS; i++) {
+ if (temps[i] < temps[i - 1]) {
+ dev_warn(dev, "fan curve: temperature decreases at point %d (%u < %u)\n",
+ i, temps[i], temps[i - 1]);
+ return -EINVAL;
+ }
+
+ if (percents[i] < percents[i - 1]) {
+ dev_warn(dev, "fan curve: pwm decreases at point %d (%u < %u)\n",
+ i, percents[i], percents[i - 1]);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static ssize_t fan_curve_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
@@ -3798,6 +3825,11 @@ static ssize_t fan_curve_enable_store(struct device *dev,
}

if (data->enabled) {
+ err = fan_curve_validate(dev, data);
+ if (err) {
+ data->enabled = false;
+ return err;
+ }
err = fan_curve_write(asus, data);
if (err)
return err;

base-commit: 6b8c8af514d739d0335f5579b585e02babe8a727
--
2.55.0