From: Armin Wolf <W_Armin@gmx.de>
To: Derek John Clark <derekjohn.clark@gmail.com>
Cc: "Mario Limonciello" <superm1@kernel.org>,
"Hans de Goede" <hdegoede@redhat.com>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Jonathan Corbet" <corbet@lwn.net>,
"Luke Jones" <luke@ljones.dev>, "Xino Ni" <nijs1@lenovo.com>,
"Zhixin Zhang" <zhangzx36@lenovo.com>,
"Mia Shao" <shaohz1@lenovo.com>,
"Mark Pearson" <mpearson-lenovo@squebb.ca>,
"Pierre-Loup A . Griffais" <pgriffais@valvesoftware.com>,
"Cody T . -H . Chiu" <codyit@gmail.com>,
"John Martens" <johnfanv2@gmail.com>,
platform-driver-x86@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH v2 0/4] platform/x86: Add Lenovo Gaming Series WMI Drivers
Date: Sat, 11 Jan 2025 01:25:04 +0100 [thread overview]
Message-ID: <fd250291-4102-4dcd-8448-d878c3a013bf@gmx.de> (raw)
In-Reply-To: <CAFqHKTmJKdZV2unLAZjRGSdjE5mB7H5ONuF2wfC9dnuFJ0R16g@mail.gmail.com>
Am 10.01.25 um 22:52 schrieb Derek John Clark:
> On Thu, Jan 9, 2025 at 3:20 PM Armin Wolf <W_Armin@gmx.de> wrote:
>> Am 02.01.25 um 19:27 schrieb Derek John Clark:
>>
>>> On Wed, Jan 1, 2025 at 8:01 PM Mario Limonciello <superm1@kernel.org> wrote:
>>>>
>>>> On 1/1/25 18:47, Derek J. Clark wrote:
>>>>> Adds support for the Lenovo "Gaming Series" of laptop hardware that use
>>>>> WMI interfaces that control various power settings. There are multiple WMI
>>>>> interfaces that work in concert to provide getting and setting values as
>>>>> well as validation of input. Currently only the "GameZone", "Other
>>>>> Mode", and "LENOVO_CAPABILITY_DATA_01" interfaces are implemented, but
>>>>> I attempted to structure the driver so that adding the "Custom Mode",
>>>>> "Lighting", and other data block interfaces would be trivial in a later
>>>>> patches.
>>>>>
>>>>> This driver is distinct from, but should be considered a replacement for
>>>>> this patch:
>>>>> https://lore.kernel.org/all/20241118100503.14228-1-jonmail@163.com/
>>>>>
>>>>> This driver attempts to standardize the exposed sysfs by mirroring the
>>>>> asus-armoury driver currently under review. As such, a lot of
>>>>> inspiration has been drawn from that driver.
>>>>> https://lore.kernel.org/all/20240930000046.51388-1-luke@ljones.dev/
>>>>>
>>>>> The drivers have been tested by me on the Lenovo Legion Go.
>>>>>
>>>>> v2:
>>>>> - Broke up initial patch into a 4 patch series.
>>>>> - Removed all references to "Legion" in documentation, Kconfig,
>>>>> driver structs, functions, etc. Everything now refers either to the
>>>>> interface being used or the Lenovo "Gaming Series" of laptop hardware.
>>>>> - Fixed all Acked changes requested by Mario and Armin.
>>>>> - Capability Data is now cached before kset creation for each attribute.
>>>>> If the lenovo-wmi-capdata01 interface is not present, fails to grab
>>>>> valid data, doesn't include the requested attribute id page, or the
>>>>> data block indicates the attribute is not supported, the attribute will
>>>>> not be created in sysfs.
>>>>> - The sysfs path for the firmware-attributes class was moved from
>>>>> lenovo-legion-wmi to lenovo-wmi-other.
>>>>>
>>>>> - The Other Mode WMI interface no longer relies on gamezone as
>>>>> discussed. However; this creates a problem that should be discussed
>>>>> here. The current_value attribute is now only accurate when the
>>>>> "custom" profile is set on the device. Previously it would report the
>>>>> value from the Capability Data 01 instance related to the currently
>>>>> selected profile, which reported an accurate accounting of the current
>>>>> system state in all cases. I submitted this as-is since we discussed
>>>>> removing that dependency, but I am not a fan of the current_value
>>>>> attribute being incorrect for 3 of the 4 available profiles, especially
>>>>> when the data is available. There is also no way to -ENOTSUPP or
>>>>> similar when not in custom mode as that would also require us to know
>>>>> the state of the gamezone interface. What I would prefer to do would be
>>>>> to make the gamezone interface optional by treating custom as the
>>>>> default mode in the current_value functions, then only update the mode
>>>>> if a callback to get the current fan profile is a success. That way the
>>>>> logic will work with or without the GameZone interface, but it will be
>>>>> greatly improved if it is present.
>>>>>
>>>> I agree there needs to be /some/ sort of dependency.
>>>> One thing I was thinking you could do is use:
>>>>
>>>> wmi_has_guid() to tell whether or not the "GZ" interface is even present
>>>> from the "Other" driver. Move the GUID for the GZ interface into a
>>>> common header both drivers include.
>>>>
>>>> However that only helps in the case of a system that supports custom but
>>>> not GZ. I think you still will need some sort of symbol to either get a
>>>> pointer to the platform profile class or tell if the profile for the
>>>> driver is set to custom.
>>>>
>>>> I personally don't see a problem with a simple symbol like this:
>>>>
>>>> bool lenovo_wmi_gamezone_is_custom(void);
>>>>
>>>> You could then have your logic in all the store and show call a helper
>>>> something like this:
>>>>
>>>> static bool lenovo_wmi_custom_mode() {
>>>> if (!wmi_has_guid(GZ_GUID)
>>>> return true;
>>>>
>>>> if (!IS_REACHABLE(CONFIG_LENOVO_WMI_GAMEZONE))
>>>> return true;
>>>>
>>>> return lenovo_wmi_gamezone_is_custom();
>>>> }
>>> I agree with checking wmi_has_guid() before calling anything across
>>> interfaces.
>> Please do not use wmi_has_guid() for this as WMI devices can disappear
>> at any time.
>>
>>> As far as using a bool to determine if we are in custom,
>>> that seems to me like that would be a half measure. Since we would be
>>> calling across interfaces anyway there is a benefit to getting the
>>> full scope, where knowing only if we are in custom or not would just
>>> add the ability to exit early. What I would prefer is knowing the
>>> specific state of the hardware as it will allow me to call the
>>> specific method ID as related to the current profile. I'll elaborate a
>>> bit on what I mean.
>>>
>>> Each attribute ID corresponds to a specific fan profile mode for a
>>> specific attribute. It is used as both the data block ID in
>>> LENOVO_CAPABILITY_DATA_01, and as the first argument when using
>>> GetFeatureValue/SetFeatureValue on the Other Mode interface. I map
>>> these with the lenovo_wmi_attr_id struct. The fan mode value provided
>>> by the gamezone interface corresponds directly to the mode value in
>>> the ID. For example, ID 0x01010100 would provide the capability data
>>> for the CPU device (0x01), SPPT (0x01), in Quiet mode (0x01). There is
>>> no type ID for these attributes (0x00) like there are on some
>>> unimplemented attributes. Balanced mode is 0x02, Performance is 0x03,
>>> Extreme mode (Which the Go doesn't use and there is no analogue for in
>>> the kernel atm) is 0xE0, and custom mode is 0xFF. When the
>>> GetSmartFanMode method ID is called on the gamezone interface it
>>> returns one of these values, corresponding to the current state of the
>>> hardware. This allows us to call GetFeatureValue for the current
>>> profile. Currently we are always calling the custom mode method ID
>>> (0x0101FF00) in GetFeatureValue.
>>>
>>> If we want to avoid an additional wmi call in GZ, then grabbing it
>>> from the platform profile and translating it back would maybe suffice.
>>> In that case I would need to implement the
>>> LENOVO_GAMEZONE_SMART_FAN_MODE_EVENT GUID
>>> "D320289E-8FEA-41E0-86F9-611D83151B5F" to ensure that the profile is
>>> updated properly when the hardware is switched profiles using the
>>> physical buttons. This is probably a good idea anyway, but some
>>> guidance on implementing that would be nice as I think it would be an
>>> additional driver and then we have more cross referencing.
>> I attached a prototype WMI driver for another device which had a similar problem.
>> The solution was to provide a notifier so other event consumers can be notified
>> when an WMI event was received.
>>
>> Example event consumer callback code:
>>
>> static int uniwill_wmi_notify_call(struct notifier_block *nb, unsigned long action, void *data)
>> {
>> if (action != UNIWILL_OSD_PERF_MODE_CHANGED)
>> return NOTIFY_DONE;
>>
>> platform_profile_cycle();
>>
>> return NOTIFY_OK;
>> }
>>
>> I would also suggest that you use a notifier for communicating with the gamezone
>> interface. Then you just have to submit commands (as action values) in the form of events
>> which will then be processed by the available gamezone drivers (the result can be stored in *data).
>>
>> Those gamezone drivers can then return NOTIFY_STOP which will ensure that only a single gamezone
>> driver can successfully process a given command.
>>
>> All in all the patch series seems to progress nicely. I am confident that we will solve the remaining issues.
>>
>> Thanks,
>> Armin Wolf
>>
> That's a novel approach. There are some EVENT GUID's for the gamezone
> interface I'll need to incorporate to keep everything in sync. These
> devices have physical buttons (Fn+Q on laptops, Legion +Y button on
> handhelds) to cycle the profiles. I didn't add this previously because
> we were always updating it when called. I presume that each GUID will
> need a separate driver for this. Any advice or examples on how to use
> this to update the pprof in GameZone would be appreciated as I've
> never used .notify before.
The WMI driver inside the attachment should be a suitable starting point.
You can also reuse the same driver for many different GUIDs and do the following:
- use the context inside the wmi_device_id to find out which GUID is being probed.
You can use drivers/platform/x86/xiaomi-wmi.c as an example.
- inside the .notify callback parse the event data and the call the notifier.
You can use the action parameter to signal which kind of WMI event was received (SMART_FAN_MODE_EVENT, ...)
and the data parameter to pass the event data.
With this you only need to provide a single WMI driver.
The lenovo-wmi-gamezone driver can then register with this notifier and listen for
platform profile changes:
static int lenovo_gz_notify_call(struct notifier_block *nb, unsigned long action, void *data)
{
if (action != SMART_FAN_MODE_EVENT) // Filter events
return NOTIFY_DONE;
<check *data if necessary>
platform_profile_cycle(); // Cycle platform profile if necessary
return NOTIFY_OK;
}
>
> My expected information flow will be these paths:
> Physical Button press -> WMI event GUID notifier driver -> Gamezone
> driver update & notify_call -> Other Mode save data to priv for lookup
> when current_value is checked and return STOP .
> or
> platform-profile class write from sysfs -> Gamezone driver update &
> notify_call ->Other Mode save data to priv for lookup when
> current_value is checked and return STOP .
>
> Thanks,
> Derek
Your approach would have a problem: how to communicate the initial platform profile state
when lenovo-wmi-other probes?
I suggest that lenovo-wmi-gamezone stores the current platform profile. This value can then
be retrieved by lenovo-wmi-other by using the special gamezone notifier. This would also allow
lenovo-wmi-other to detect when lenovo-wmi-gamezone is not ready and can thus not provide
platform profile data.
Thanks,
Armin Wolf
>
>>> The simplest solution IMO would be to do something closer to what I
>>> was doing in v1 just for current_value_show, where we instantiate the
>>> mode variable as SMARTFAN_MODE_CUSTOM (0xFF) then check if the gz
>>> interface is present. If it is, pass the mode variable as a pointer to
>>> GZ where it can call GetSmartFanMode and update the value. Otherwise,
>>> bypass that block and treat it as custom. This does add an additional
>>> WMI call, but only when reading the current_value.
>>>
>>>>> - I did extensive testing of this firmware-attributes interface and its
>>>>> ability to retain the value set by the user. The SPL, SPPT, FPPT, and
>>>>> platform profile all retain the users last setting when resuming from
>>>>> suspend, a full reboot, and a full shutdown. The only time the values
>>>>> are not preserved is when the user manually selects a new platform
>>>>> profile using either the pprof interface or the manual selection
>>>>> button on the device, in which case you would not expect them to be
>>>>> retained as they were intentionally changed. Based on the previous
>>>>> discussion it may be the case that older BIOS' will preserve the
>>>>> settings even after changing profiles, though I haven't confirmed
>>>>> this.
>>>> This is good to hear considering the concerns raised by some others.
>>>>
>>>> But FWIW we have nothing in the firmware attributes API documentation
>>>> that mandates what the firmware does for storage of settings across a
>>>> power cycle so this is currently up to the platform to decide.
>>>>> v1:
>>>>> https://lore.kernel.org/platform-driver-x86/CAFqHKTna+kJpHLo5s4Fm1TmHcSSqSTr96JHDm0DJ0dxsZMkixA@mail.gmail.com/T/#t
>>>>>
>>>>> Suggested-by: Mario Limonciello <superm1@kernel.org>
>>>>> Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
>>>>>
>>>>> Derek J. Clark (4):
>>>>> platform/x86: Add lenovo-wmi drivers Documentation
>>>>> platform/x86: Add Lenovo GameZone WMI Driver
>>>>> platform/x86: Add Lenovo Capability Data 01 WMI Driver
>>>>> platform/x86: Add Lenovo Other Mode WMI Driver
>>>>>
>>>>> Documentation/wmi/devices/lenovo-wmi.rst | 104 ++++++
>>>>> MAINTAINERS | 9 +
>>>>> drivers/platform/x86/Kconfig | 34 ++
>>>>> drivers/platform/x86/Makefile | 3 +
>>>>> drivers/platform/x86/lenovo-wmi-capdata01.c | 131 +++++++
>>>>> drivers/platform/x86/lenovo-wmi-gamezone.c | 203 +++++++++++
>>>>> drivers/platform/x86/lenovo-wmi-other.c | 385 ++++++++++++++++++++
>>>>> drivers/platform/x86/lenovo-wmi.h | 241 ++++++++++++
>>>>> 8 files changed, 1110 insertions(+)
>>>>> create mode 100644 Documentation/wmi/devices/lenovo-wmi.rst
>>>>> create mode 100644 drivers/platform/x86/lenovo-wmi-capdata01.c
>>>>> create mode 100644 drivers/platform/x86/lenovo-wmi-gamezone.c
>>>>> create mode 100644 drivers/platform/x86/lenovo-wmi-other.c
>>>>> create mode 100644 drivers/platform/x86/lenovo-wmi.h
>>>>>
next prev parent reply other threads:[~2025-01-11 0:25 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-02 0:47 Derek J. Clark
2025-01-02 0:47 ` [PATCH v2 1/4] platform/x86: Add lenovo-wmi drivers Documentation Derek J. Clark
2025-01-02 3:46 ` Mario Limonciello
2025-01-09 21:36 ` Armin Wolf
2025-01-10 22:41 ` Derek John Clark
2025-01-10 23:21 ` Armin Wolf
2025-01-02 0:47 ` [PATCH v2 2/4] platform/x86: Add Lenovo GameZone WMI Driver Derek J. Clark
2025-01-02 4:09 ` Mario Limonciello
2025-01-02 18:44 ` Derek John Clark
2025-01-02 19:10 ` Mario Limonciello
2025-01-09 22:11 ` Armin Wolf
2025-01-10 21:33 ` Derek John Clark
2025-01-10 23:23 ` Armin Wolf
2025-01-12 3:25 ` Derek John Clark
2025-01-10 12:27 ` Ilpo Järvinen
2025-01-10 21:34 ` Derek John Clark
2025-01-02 0:47 ` [PATCH v2 3/4] platform/x86: Add Lenovo Capability Data 01 " Derek J. Clark
2025-01-02 3:44 ` Mario Limonciello
2025-01-02 18:42 ` Derek John Clark
2025-01-09 22:34 ` Armin Wolf
2025-01-10 22:11 ` Derek John Clark
2025-01-11 0:01 ` Armin Wolf
2025-01-02 0:47 ` [PATCH v2 4/4] platform/x86: Add Lenovo Other Mode " Derek J. Clark
2025-01-02 3:40 ` Mario Limonciello
2025-01-02 18:49 ` Derek John Clark
2025-01-07 18:21 ` Ilpo Järvinen
2025-01-07 23:55 ` Derek John Clark
2025-01-08 9:37 ` Ilpo Järvinen
2025-01-02 9:33 ` kernel test robot
2025-01-09 23:00 ` Armin Wolf
2025-01-10 22:33 ` Derek John Clark
2025-01-11 0:10 ` Armin Wolf
2025-01-11 17:29 ` Derek John Clark
2025-01-02 4:01 ` [PATCH v2 0/4] platform/x86: Add Lenovo Gaming Series WMI Drivers Mario Limonciello
2025-01-02 18:27 ` Derek John Clark
2025-01-09 23:20 ` Armin Wolf
2025-01-10 21:52 ` Derek John Clark
2025-01-11 0:25 ` Armin Wolf [this message]
2025-01-11 17:13 ` Derek John Clark
2025-01-08 23:09 ` Armin Wolf
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=fd250291-4102-4dcd-8448-d878c3a013bf@gmx.de \
--to=w_armin@gmx.de \
--cc=codyit@gmail.com \
--cc=corbet@lwn.net \
--cc=derekjohn.clark@gmail.com \
--cc=hdegoede@redhat.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=johnfanv2@gmail.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luke@ljones.dev \
--cc=mpearson-lenovo@squebb.ca \
--cc=nijs1@lenovo.com \
--cc=pgriffais@valvesoftware.com \
--cc=platform-driver-x86@vger.kernel.org \
--cc=shaohz1@lenovo.com \
--cc=superm1@kernel.org \
--cc=zhangzx36@lenovo.com \
/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®