On Mon, 12 May 2025 at 01:34, Kurt Borja <kuurtb@xxxxxxxxx> wrote: > > On Sun May 11, 2025 at 5:44 PM -03, Antheas Kapenekakis wrote: > > MSI's version of platform profile in Windows is called shift mode. > > Introduce it here, and add a profile handler to it. > > > > It has 5 modes: sport, comfort, green, eco, and user. > > Confusingly, for the Claw, MSI only uses sport, green, and eco, > > where they correspond to performance, balanced, and low-power. > > Therefore, comfort is mapped to balanced-performance, and user to > > custom. > > > > Signed-off-by: Antheas Kapenekakis <lkml@xxxxxxxxxxx> > > --- > > drivers/platform/x86/Kconfig | 1 + > > drivers/platform/x86/msi-wmi-platform.c | 117 ++++++++++++++++++++++++ > > 2 files changed, 118 insertions(+) > > > > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig > > index bee98251b8f0b..57a48910c8fd4 100644 > > --- a/drivers/platform/x86/Kconfig > > +++ b/drivers/platform/x86/Kconfig > > @@ -746,6 +746,7 @@ config MSI_WMI_PLATFORM > > tristate "MSI WMI Platform features" > > depends on ACPI_WMI > > depends on HWMON > > + select ACPI_PLATFORM_PROFILE > > help > > Say Y here if you want to have support for WMI-based platform features > > like fan sensor access on MSI machines. > > diff --git a/drivers/platform/x86/msi-wmi-platform.c b/drivers/platform/x86/msi-wmi-platform.c > > index 9ac3c6f1b3f1d..c0b577c95c079 100644 > > --- a/drivers/platform/x86/msi-wmi-platform.c > > +++ b/drivers/platform/x86/msi-wmi-platform.c > > @@ -17,6 +17,7 @@ > > #include <linux/dmi.h> > > #include <linux/errno.h> > > #include <linux/fixp-arith.h> > > +#include <linux/platform_profile.h> > > #include <linux/hwmon.h> > > #include <linux/hwmon-sysfs.h> > > #include <linux/kernel.h> > > @@ -63,6 +64,16 @@ > > #define MSI_PLATFORM_AP_FAN_FLAGS_OFFSET 1 > > #define MSI_PLATFORM_AP_ENABLE_FAN_TABLES BIT(7) > > > > +/* Get_Data() and Set_Data() Shift Mode Register */ > > Maybe you can write short documentation for these methods? > > > +#define MSI_PLATFORM_SHIFT_ADDR 0xd2 > > +#define MSI_PLATFORM_SHIFT_DISABLE BIT(7) > > +#define MSI_PLATFORM_SHIFT_ENABLE (BIT(7) | BIT(6)) > > +#define MSI_PLATFORM_SHIFT_SPORT (MSI_PLATFORM_SHIFT_ENABLE + 4) > > +#define MSI_PLATFORM_SHIFT_COMFORT (MSI_PLATFORM_SHIFT_ENABLE + 0) > > +#define MSI_PLATFORM_SHIFT_GREEN (MSI_PLATFORM_SHIFT_ENABLE + 1) > > +#define MSI_PLATFORM_SHIFT_ECO (MSI_PLATFORM_SHIFT_ENABLE + 2) > > +#define MSI_PLATFORM_SHIFT_USER (MSI_PLATFORM_SHIFT_ENABLE + 3) > > Instead of summing the profiles I suggest something like: > > enum MSI_PLATFORM_PROFILES { > MSI_PROFILE_COMFORT, > MSI_PROFILE_GREEN, > MSI_PROFILE_ECO, > MSI_PROFILE_USER, > MSI_PROFILE_SPORT, > } > > And you can prepare your commands like > > command = MSI_PLATFORM_SHIT_ENABLE; > command |= FIELD_PREP(GENMASK(1,0), MSI_PROFILE_{profile}); > > I feel that it's cleaner this way. This is only a suggestion though. > > > + > > static bool force; > > module_param_unsafe(force, bool, 0); > > MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions"); > > @@ -100,12 +111,14 @@ enum msi_wmi_platform_method { > > }; > > > > struct msi_wmi_platform_quirk { > > + bool shift_mode; /* Shift mode is supported */ > > }; > > > > 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_debugfs_data { > > @@ -150,8 +163,10 @@ static const char * const msi_wmi_platform_debugfs_names[] = { > > > > static struct msi_wmi_platform_quirk quirk_default = {}; > > static struct msi_wmi_platform_quirk quirk_gen1 = { > > + .shift_mode = true > > }; > > static struct msi_wmi_platform_quirk quirk_gen2 = { > > + .shift_mode = true > > }; > > > > static const struct dmi_system_id msi_quirks[] = { > > @@ -561,6 +576,90 @@ static const struct hwmon_chip_info msi_wmi_platform_chip_info = { > > .info = msi_wmi_platform_info, > > }; > > > > +static int msi_wmi_platform_profile_probe(void *drvdata, unsigned long *choices) > > +{ > > + set_bit(PLATFORM_PROFILE_LOW_POWER, choices); > > + set_bit(PLATFORM_PROFILE_BALANCED, choices); > > + set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices); > > + set_bit(PLATFORM_PROFILE_PERFORMANCE, choices); > > Please, use the non-atomic __set_bit(). `choices` is not shared between > threads. > > > + return 0; > > +} > > + > > +static int msi_wmi_platform_profile_get(struct device *dev, > > + enum platform_profile_option *profile) > > +{ > > + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); > > + int ret; > > + > > + u8 buffer[32] = { }; > > Move this to the top. > > > + > > + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; > > + > > + ret = msi_wmi_platform_query(data, MSI_PLATFORM_GET_DATA, buffer, sizeof(buffer)); > > + if (ret < 0) > > + return ret; > > + > > + if (buffer[0] != 1) > > + return -EINVAL; > > + > > + switch (buffer[1]) { > > + case MSI_PLATFORM_SHIFT_SPORT: > > + *profile = PLATFORM_PROFILE_PERFORMANCE; > > + return 0; > > + case MSI_PLATFORM_SHIFT_COMFORT: > > + *profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE; > > Maybe comfort can be mapped to balanced and green to cool. What do you > think? I forgot to comment on this one. The Claw uses ECO, GREEN, and PERFORMANCE as its primary modes with 8, 12, 30W respectively. Comfort is not used specifically for it. So I chose to push Green upwards to balanced. @Armin might know more about this one. If it turns out using comfort for balanced fits better for laptops we can do that instead. Antheas > > > + return 0; > > + case MSI_PLATFORM_SHIFT_GREEN: > > + *profile = PLATFORM_PROFILE_BALANCED; > > + return 0; > > + case MSI_PLATFORM_SHIFT_ECO: > > + *profile = PLATFORM_PROFILE_LOW_POWER; > > + return 0; > > + case MSI_PLATFORM_SHIFT_USER: > > + *profile = PLATFORM_PROFILE_CUSTOM; > > + return 0; > > + default: > > + return -EINVAL; > > + } > > +} > > + > > +static int msi_wmi_platform_profile_set(struct device *dev, > > + enum platform_profile_option profile) > > +{ > > + struct msi_wmi_platform_data *data = dev_get_drvdata(dev); > > + u8 buffer[32] = { }; > > + > > + buffer[0] = MSI_PLATFORM_SHIFT_ADDR; > > + > > + switch (profile) { > > + case PLATFORM_PROFILE_PERFORMANCE: > > + buffer[1] = MSI_PLATFORM_SHIFT_SPORT; > > + break; > > + case PLATFORM_PROFILE_BALANCED_PERFORMANCE: > > + buffer[1] = MSI_PLATFORM_SHIFT_COMFORT; > > + break; > > + case PLATFORM_PROFILE_BALANCED: > > + buffer[1] = MSI_PLATFORM_SHIFT_GREEN; > > + break; > > + case PLATFORM_PROFILE_LOW_POWER: > > + buffer[1] = MSI_PLATFORM_SHIFT_ECO; > > + break; > > + case PLATFORM_PROFILE_CUSTOM: > > + buffer[1] = MSI_PLATFORM_SHIFT_USER; > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + return msi_wmi_platform_query(data, MSI_PLATFORM_SET_DATA, buffer, sizeof(buffer)); > > +} > > + > > +static const struct platform_profile_ops msi_wmi_platform_profile_ops = { > > + .probe = msi_wmi_platform_profile_probe, > > + .profile_get = msi_wmi_platform_profile_get, > > + .profile_set = msi_wmi_platform_profile_set, > > +}; > > + > > static ssize_t msi_wmi_platform_debugfs_write(struct file *fp, const char __user *input, > > size_t length, loff_t *offset) > > { > > @@ -742,6 +841,22 @@ static int msi_wmi_platform_init(struct msi_wmi_platform_data *data) > > return 0; > > } > > > > +static int msi_wmi_platform_profile_setup(struct msi_wmi_platform_data *data) > > +{ > > + int err; > > + > > + if (!data->quirks->shift_mode) > > + return 0; > > + > > + data->ppdev = devm_platform_profile_register( > > + &data->wdev->dev, "msi-wmi-platform", data, > > + &msi_wmi_platform_profile_ops); > > Broken format. > > > + if (err) > > + return err; > > `err` is not initialized. Is it a leftover? > > > + > > + return PTR_ERR_OR_ZERO(data->ppdev); > > +} > > + > > static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) > > { > > struct msi_wmi_platform_data *data; > > @@ -775,6 +890,8 @@ static int msi_wmi_platform_probe(struct wmi_device *wdev, const void *context) > > > > msi_wmi_platform_debugfs_init(data); > > > > + msi_wmi_platform_profile_setup(data); > > Check return value. > > -- > ~ Kurt > > > + > > return msi_wmi_platform_hwmon_init(data); > > } > > >