mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Antheas Kapenekakis <lkml@antheas.dev>
To: platform-driver-x86@vger.kernel.org
Cc: "Armin Wolf" <W_Armin@gmx.de>, "Jonathan Corbet" <corbet@lwn.net>,
	"Hans de Goede" <hdegoede@redhat.com>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"Jean Delvare" <jdelvare@suse.com>,
	"Guenter Roeck" <linux@roeck-us.net>,
	"Kurt Borja" <kuurtb@gmail.com>,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-hwmon@vger.kernel.org,
	"Antheas Kapenekakis" <lkml@antheas.dev>
Subject: [PATCH v1 10/10] platform/x86: msi-wmi-platform: Restore fan curves on PWM disable and unload
Date: Sun, 11 May 2025 22:44:27 +0200	[thread overview]
Message-ID: <20250511204427.327558-11-lkml@antheas.dev> (raw)
In-Reply-To: <20250511204427.327558-1-lkml@antheas.dev>

MSI software is a bit weird in that even when the manual fan curve is
disabled, the fan speed is still somewhat affected by the curve. So
we have to restore the fan curves on unload and PWM disable, as it
is done in Windows.

Suggested-by: Armin Wolf <W_Armin@gmx.de>
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
---
 drivers/platform/x86/msi-wmi-platform.c | 123 +++++++++++++++++++++++-
 1 file changed, 122 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/msi-wmi-platform.c b/drivers/platform/x86/msi-wmi-platform.c
index 7dafe17d4d6be..a917db0300c06 100644
--- a/drivers/platform/x86/msi-wmi-platform.c
+++ b/drivers/platform/x86/msi-wmi-platform.c
@@ -123,16 +123,25 @@ struct msi_wmi_platform_quirk {
 	bool shift_mode;	/* Shift mode is supported */
 	bool charge_threshold;	/* Charge threshold is supported */
 	bool dual_fans;		/* For devices with two hwmon fans */
+	bool restore_curves;	/* Restore factory curves on unload */
 	int pl_min;		/* Minimum PLx value */
 	int pl1_max;		/* Maximum PL1 value */
 	int pl2_max;		/* Maximum PL2 value */
 };
 
+struct msi_wmi_platform_factory_curves {
+	u8 cpu_fan_table[32];
+	u8 gpu_fan_table[32];
+	u8 cpu_temp_table[32];
+	u8 gpu_temp_table[32];
+};
+
 struct msi_wmi_platform_data {
 	struct wmi_device *wdev;
 	struct msi_wmi_platform_quirk *quirks;
 	struct mutex wmi_lock;	/* Necessary when calling WMI methods */
 	struct device *ppdev;
+	struct msi_wmi_platform_factory_curves factory_curves;
 	struct acpi_battery_hook battery_hook;
 	struct device *fw_attrs_dev;
 	struct kset *fw_attrs_kset;
@@ -219,6 +228,7 @@ static struct msi_wmi_platform_quirk quirk_gen1 = {
 	.shift_mode = true,
 	.charge_threshold = true,
 	.dual_fans = true,
+	.restore_curves = true,
 	.pl_min = 8,
 	.pl1_max = 43,
 	.pl2_max = 45
@@ -227,6 +237,7 @@ static struct msi_wmi_platform_quirk quirk_gen2 = {
 	.shift_mode = true,
 	.charge_threshold = true,
 	.dual_fans = true,
+	.restore_curves = true,
 	.pl_min = 8,
 	.pl1_max = 30,
 	.pl2_max = 37
@@ -507,6 +518,94 @@ static struct attribute *msi_wmi_platform_hwmon_attrs[] = {
 };
 ATTRIBUTE_GROUPS(msi_wmi_platform_hwmon);
 
+static int msi_wmi_platform_curves_save(struct msi_wmi_platform_data *data)
+{
+	int ret;
+
+	data->factory_curves.cpu_fan_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_CPU_FAN_TABLE;
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_GET_FAN,
+		data->factory_curves.cpu_fan_table,
+		sizeof(data->factory_curves.cpu_fan_table));
+	if (ret < 0)
+		return ret;
+	data->factory_curves.cpu_fan_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_CPU_FAN_TABLE;
+
+	data->factory_curves.gpu_fan_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_GPU_FAN_TABLE;
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_GET_FAN,
+		data->factory_curves.gpu_fan_table,
+		sizeof(data->factory_curves.gpu_fan_table));
+	if (ret < 0)
+		return ret;
+	data->factory_curves.gpu_fan_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_GPU_FAN_TABLE;
+
+	data->factory_curves.cpu_temp_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_CPU_TEMP_TABLE;
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_GET_TEMPERATURE,
+		data->factory_curves.cpu_temp_table,
+		sizeof(data->factory_curves.cpu_temp_table));
+	if (ret < 0)
+		return ret;
+	data->factory_curves.cpu_temp_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_CPU_TEMP_TABLE;
+
+	data->factory_curves.gpu_temp_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_GPU_TEMP_TABLE;
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_GET_TEMPERATURE,
+		data->factory_curves.gpu_temp_table,
+		sizeof(data->factory_curves.gpu_temp_table));
+	if (ret < 0)
+		return ret;
+	data->factory_curves.gpu_temp_table[0] =
+		MSI_PLATFORM_FAN_SUBFEATURE_GPU_TEMP_TABLE;
+
+	return 0;
+}
+
+static int msi_wmi_platform_curves_load(struct msi_wmi_platform_data *data)
+{
+	u8 buffer[32] = { };
+	int ret;
+
+	memcpy(buffer, data->factory_curves.cpu_fan_table,
+	       sizeof(data->factory_curves.cpu_fan_table));
+	ret = msi_wmi_platform_query_unlocked(data, MSI_PLATFORM_SET_FAN,
+					      buffer, sizeof(buffer));
+	if (ret < 0)
+		return ret;
+
+	memcpy(buffer, data->factory_curves.gpu_fan_table,
+	       sizeof(data->factory_curves.gpu_fan_table));
+	ret = msi_wmi_platform_query_unlocked(data, MSI_PLATFORM_SET_FAN,
+					      buffer, sizeof(buffer));
+	if (ret < 0)
+		return ret;
+
+	memcpy(buffer, data->factory_curves.cpu_temp_table,
+	       sizeof(data->factory_curves.cpu_temp_table));
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_SET_TEMPERATURE, buffer, sizeof(buffer));
+	if (ret < 0)
+		return ret;
+
+	memcpy(buffer, data->factory_curves.gpu_temp_table,
+	       sizeof(data->factory_curves.gpu_temp_table));
+	ret = msi_wmi_platform_query_unlocked(
+		data, MSI_PLATFORM_SET_TEMPERATURE, buffer, sizeof(buffer));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+
 static umode_t msi_wmi_platform_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 					   u32 attr, int channel)
 {
@@ -603,9 +702,19 @@ static int msi_wmi_platform_write(struct device *dev, enum hwmon_sensor_types ty
 				return -EINVAL;
 			}
 
-			return msi_wmi_platform_query_unlocked(
+			ret = msi_wmi_platform_query_unlocked(
 				data, MSI_PLATFORM_SET_AP, buffer,
 				sizeof(buffer));
+			if (ret < 0)
+				return ret;
+
+			if (val == 2 && data->quirks->restore_curves) {
+				ret = msi_wmi_platform_curves_load(data);
+				if (ret < 0)
+					return ret;
+			}
+
+			return 0;
 		default:
 			return -EOPNOTSUPP;
 		}
@@ -1373,6 +1482,13 @@ static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context)
 
 	msi_wmi_platform_profile_setup(data);
 
+	if (data->quirks->restore_curves) {
+		guard(mutex)(&data->wmi_lock);
+		ret = msi_wmi_platform_curves_save(data);
+		if (ret < 0)
+			return ret;
+	}
+
 	return msi_wmi_platform_hwmon_init(data);
 }
 
@@ -1382,6 +1498,11 @@ static void msi_wmi_platform_remove(struct wmi_device *wdev)
 
 	if (data->quirks->charge_threshold)
 		battery_hook_unregister(&data->battery_hook);
+
+	if (data->quirks->restore_curves) {
+		guard(mutex)(&data->wmi_lock);
+		msi_wmi_platform_curves_load(data);
+	}
 }
 
 static const struct wmi_device_id msi_wmi_platform_id_table[] = {
-- 
2.49.0


  parent reply	other threads:[~2025-05-11 20:45 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-11 20:44 [PATCH v1 00/10] platform/x86: msi-wmi-platform: Add fan curves/platform profile/tdp/battery limiting Antheas Kapenekakis
2025-05-11 20:44 ` [PATCH v1 01/10] platform/x86: msi-wmi-platform: Use input buffer for returning result Antheas Kapenekakis
2025-05-11 23:31   ` Kurt Borja
2025-05-13 19:42     ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 02/10] platform/x86: msi-wmi-platform: Add unlocked msi_wmi_platform_query Antheas Kapenekakis
2025-05-12 19:21   ` Kurt Borja
2025-05-12 20:51     ` Antheas Kapenekakis
2025-05-12 21:23       ` Kurt Borja
2025-05-12 21:51         ` Antheas Kapenekakis
2025-05-13 19:45     ` Armin Wolf
2025-05-13 19:47   ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 03/10] platform/x86: msi-wmi-platform: Add quirk system Antheas Kapenekakis
2025-05-11 23:32   ` Kurt Borja
2025-05-13 20:43   ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 04/10] platform/x86: msi-wmi-platform: Add support for fan control Antheas Kapenekakis
2025-05-11 23:32   ` Kurt Borja
2025-05-13 20:58   ` Armin Wolf
2025-05-19  1:35     ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 05/10] platform/x86: msi-wmi-platform: Add platform profile through shift mode Antheas Kapenekakis
2025-05-11 23:33   ` Kurt Borja
2025-05-12 21:59     ` Antheas Kapenekakis
2025-05-19  1:51       ` Armin Wolf
2025-05-19  1:58   ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 06/10] platform/x86: msi-wmi-platform: Add PL1/PL2 support via firmware attributes Antheas Kapenekakis
2025-05-11 23:34   ` Kurt Borja
2025-05-12 10:22     ` Antheas Kapenekakis
2025-05-19  2:08   ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 07/10] platform/x86: msi-wmi-platform: Add charge_threshold support Antheas Kapenekakis
2025-05-11 23:34   ` Kurt Borja
2025-05-19  2:32   ` Armin Wolf
2025-05-11 20:44 ` [PATCH v1 08/10] platform/x86: msi-wmi-platform: Drop excess fans in dual fan devices Antheas Kapenekakis
2025-05-11 23:35   ` Kurt Borja
2025-05-11 20:44 ` [PATCH v1 09/10] platform/x86: msi-wmi-platform: Update header text Antheas Kapenekakis
2025-05-19  2:33   ` Armin Wolf
2025-05-11 20:44 ` Antheas Kapenekakis [this message]
2025-05-12 19:16   ` [PATCH v1 10/10] platform/x86: msi-wmi-platform: Restore fan curves on PWM disable and unload Kurt Borja
2025-05-12 20:50     ` Antheas Kapenekakis
2025-05-11 23:30 ` [PATCH v1 00/10] platform/x86: msi-wmi-platform: Add fan curves/platform profile/tdp/battery limiting Kurt Borja
2025-05-12 10:16   ` Antheas Kapenekakis
2025-05-12 19:05     ` Kurt Borja
2025-05-19  2:37 ` Armin Wolf
2025-05-30 20:50   ` Antheas Kapenekakis
2025-05-30 21:15     ` Armin Wolf
2025-05-30 21:28       ` Antheas Kapenekakis
2025-05-30 22:00         ` Armin Wolf
2026-05-08 18:41 ` Derek J. Clark
2026-05-09 17:25   ` Antheas Kapenekakis
2026-08-03 22:16 ` [PATCH 0/6] " Derek J. Clark
2026-08-03 22:16   ` [PATCH 1/6] platform/x86: msi-wmi-platform: Move guard out of switch in platform_write() Derek J. Clark
2026-08-18 14:12     ` Ilpo Järvinen
2026-08-18 14:42       ` Guenter Roeck
2026-08-18 15:20         ` Derek John Clark
2026-08-18 15:26         ` Antheas Kapenekakis
2026-08-03 22:16   ` [PATCH 2/6] platform/x86: msi-wmi-platform: fix: Remove unused err Derek J. Clark
2026-08-03 22:16   ` [PATCH 3/6] platform/x86: msi-wmi-platform: terminate msi_quirks DMI table Derek J. Clark
2026-08-03 22:16   ` [PATCH 4/6] platform/x86: msi-wmi-platform: Clean up devices Derek J. Clark
2026-08-03 22:16   ` [PATCH 5/6] platform/x86: wmi-msi-platform: Add MSI Claw A8 support Derek J. Clark
2026-08-03 22:16   ` [PATCH 6/6] platform-x86: msi-wmi-platform: Add Gen 4 device Derek J. Clark
2026-08-05 17:41   ` [PATCH 0/6] Re: [PATCH v1 00/10] platform/x86: msi-wmi-platform: Add fan curves/platform profile/tdp/battery limiting Antheas Kapenekakis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250511204427.327558-11-lkml@antheas.dev \
    --to=lkml@antheas.dev \
    --cc=W_Armin@gmx.de \
    --cc=corbet@lwn.net \
    --cc=hdegoede@redhat.com \
    --cc=ilpo.jarvinen@linux.intel.com \
    --cc=jdelvare@suse.com \
    --cc=kuurtb@gmail.com \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=platform-driver-x86@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®