mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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
>>>>>

  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®