linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/9] platform/x86: introduce asus-armoury driver
@ 2024-09-26  9:29 Luke D. Jones
  2024-09-26  9:29 ` [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI Luke D. Jones
                   ` (9 more replies)
  0 siblings, 10 replies; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

his is the first major patch I've ever done with the intention of
introducing a new module, so it's highly likely I've made some mistakes
or misunderstood something.

TL;DR:
1. introduce new module to contain bios attributes, using fw_attributes_class
2. deprecate all possible attributes from asus-wmi that were added ad-hoc
3. remove those in the next LTS cycle

The idea for this originates from a conversation with Mario Limonciello
https://lore.kernel.org/platform-driver-x86/371d4109-a3bb-4c3b-802f-4ec27a945c99@amd.com/

It is without a doubt much cleaner to use, easier to discover, and the
API is well defined as opposed to the random clutter of attributes I had
been placing in the platform sysfs.

There is some discussion on-going regarding the way tuning knobs such as
the PPT_* should work with platform_profile. This may result in the creation
of an extra profile type "Custom" to signify that the user has adjusted
things away from the defaults used by profiles such as "balanced" or "quiet".

Regards,
Luke

Changelog:
- v1
  - Initial submission
- v2
  - Too many changes to list, but all concerns raised in previous submission addressed.
  - History: https://lore.kernel.org/platform-driver-x86/20240716051612.64842-1-luke@ljones.dev/
- v3
  - All concerns addressed.
  - History: https://lore.kernel.org/platform-driver-x86/20240806020747.365042-1-luke@ljones.dev/
- v4
  - Use EXPORT_SYMBOL_NS_GPL() for the symbols required in this patch series
  - Add patch for hid-asus due to the use of EXPORT_SYMBOL_NS_GPL()
  - Split the PPT knobs out to a separate patch
  - Split the hd_panel setting out to a new patch
  - Clarify some of APU MEM configuration and convert int to hex
  - Rename deprecated Kconfig option to ASUS_WMI_DEPRECATED_ATTRS
  - Fixup cyclic dependency in Kconfig

Luke D. Jones (9):
  platform/x86: asus-wmi: export symbols used for read/write WMI
  hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI)
  platform/x86: asus-armoury: move existing tunings to asus-armoury
    module
  platform/x86: asus-armoury: add panel_hd_mode attribute
  platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
  platform/x86: asus-armoury: add dgpu tgp control
  platform/x86: asus-armoury: add apu-mem control support
  platform/x86: asus-armoury: add core count control
  platform/x86: asus-wmi: deprecate bios features

 .../ABI/testing/sysfs-platform-asus-wmi       |   17 +
 drivers/hid/hid-asus.c                        |    1 +
 drivers/platform/x86/Kconfig                  |   22 +
 drivers/platform/x86/Makefile                 |    1 +
 drivers/platform/x86/asus-armoury.c           | 1051 +++++++++++++++++
 drivers/platform/x86/asus-armoury.h           |  257 ++++
 drivers/platform/x86/asus-wmi.c               |  185 ++-
 include/linux/platform_data/x86/asus-wmi.h    |   19 +
 8 files changed, 1520 insertions(+), 33 deletions(-)
 create mode 100644 drivers/platform/x86/asus-armoury.c
 create mode 100644 drivers/platform/x86/asus-armoury.h

-- 
2.46.1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:26   ` Mario Limonciello
  2024-09-26  9:29 ` [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI) Luke D. Jones
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

Export some rather helpful read/write WMI symbols using a namespace.
These are DEVS and DSTS only, or require the arg0 input.

Also does a slight refactor of internals of these functions.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-wmi.c            | 51 ++++++++++++++++++++--
 include/linux/platform_data/x86/asus-wmi.h | 10 +++++
 2 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 6725a27df62f..0a5221d65130 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -385,7 +385,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
 {
 	return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
 }
-EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
+EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, ASUS_WMI);
 
 static int asus_wmi_evaluate_method5(u32 method_id,
 		u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval)
@@ -549,12 +549,57 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
 	return 0;
 }
 
-static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
-				 u32 *retval)
+/**
+ * asus_wmi_get_devstate_dsts() - Get the WMI function state.
+ * @dev_id: The WMI function to call.
+ * @retval: A pointer to where to store the value returned from WMI.
+ *
+ * The returned WMI function state can also be used to determine if the WMI
+ * function is supported by checking if the asus_wmi_get_devstate_dsts()
+ * returns an error.
+ *
+ * On success the return value is 0, and the retval is a valid value returned
+ * by the successful WMI function call. An error value is returned only if the
+ * WMI function failed, or if it returns "unsupported" which is typically a 0
+ * (no return, and no 'supported' bit set), or a 0xFFFFFFFE (~1) which if not
+ * caught here can result in unexpected behaviour later.
+ */
+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
+{
+	int err;
+
+	err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval);
+	if (err)
+		return err;
+
+	*retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
+	if (*retval == ASUS_WMI_UNSUPPORTED_METHOD)
+		return -ENODEV;
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, ASUS_WMI);
+
+/**
+ * asus_wmi_set_devstate() - Set the WMI function state.
+ * @dev_id: The WMI function to call.
+ * @ctrl_param: The argument to be used for this WMI function.
+ * @retval: A pointer to where to store the value returned from WMI.
+ *
+ * The returned WMI function state if not checked here for error as
+ * asus_wmi_set_devstate() is not called unless first paired with a call to
+ * asus_wmi_get_devstate_dsts() to check that the WMI function is supported.
+ *
+ * On success the return value is 0, and the retval is a valid value returned
+ * by the successful WMI function call. An error value is returned only if the
+ * WMI function failed.
+ */
+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
 {
 	return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
 					ctrl_param, retval);
 }
+EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, ASUS_WMI);
 
 /* Helper for special devices with magic return codes */
 static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 365e119bebaa..6ea4dedfb85e 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -158,8 +158,18 @@
 #define ASUS_WMI_DSTS_LIGHTBAR_MASK	0x0000000F
 
 #if IS_REACHABLE(CONFIG_ASUS_WMI)
+int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval);
+int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
 int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
 #else
+static inline int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
+{
+	return -ENODEV;
+}
+static inline int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
+{
+	return -ENODEV;
+}
 static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
 					   u32 *retval)
 {
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI)
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
  2024-09-26  9:29 ` [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 11:54   ` Jiri Kosina
  2024-09-26  9:29 ` [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

A small change to asus_wmi_evaluate_method() was introduced during
asus-armoury driver development to put the exports behind a namespace.

Import that namespace here.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/hid/hid-asus.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index a4b47319ad8e..9540e3e19cce 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1301,4 +1301,5 @@ static struct hid_driver asus_driver = {
 };
 module_hid_driver(asus_driver);
 
+MODULE_IMPORT_NS(ASUS_WMI);
 MODULE_LICENSE("GPL");
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
  2024-09-26  9:29 ` [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI Luke D. Jones
  2024-09-26  9:29 ` [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI) Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:48   ` Mario Limonciello
  2024-09-26 19:10   ` Markus Elfring
  2024-09-26  9:29 ` [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute Luke D. Jones
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

The fw_attributes_class provides a much cleaner interface to all of the
attributes introduced to asus-wmi. This patch moves all of these extra
attributes over to fw_attributes_class, and shifts the bulk of these
definitions to a new kernel module to reduce the clutter of asus-wmi
with the intention of deprecating the asus-wmi attributes in future.

The work applies only to WMI methods which don't have a clearly defined
place within the sysfs and as a result ended up lumped together in
/sys/devices/platform/asus-nb-wmi/ with no standard API.

Where possible the fw attrs now implement defaults, min, max, scalar,
choices, etc. As en example dgpu_disable becomes:

/sys/class/firmware-attributes/asus-armoury/attributes/dgpu_disable/
├── current_value
├── display_name
├── possible_values
└── type

as do other attributes.

The ppt_* based attributes are removed in this initial patch as the
implementation is somewhat broken due to the WMI methods requiring a
set of limits on the values accepted (which is not provided by WMI).

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/Kconfig        |  13 +
 drivers/platform/x86/Makefile       |   1 +
 drivers/platform/x86/asus-armoury.c | 563 ++++++++++++++++++++++++++++
 drivers/platform/x86/asus-armoury.h | 146 ++++++++
 4 files changed, 723 insertions(+)
 create mode 100644 drivers/platform/x86/asus-armoury.c
 create mode 100644 drivers/platform/x86/asus-armoury.h

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 3875abba5a79..dedf66e0d099 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -265,6 +265,19 @@ config ASUS_WIRELESS
 	  If you choose to compile this driver as a module the module will be
 	  called asus-wireless.
 
+config ASUS_ARMOURY
+	tristate "ASUS Armoury driver"
+	depends on ACPI_WMI
+	depends on ASUS_WMI
+	select FW_ATTR_CLASS
+	help
+	  Say Y here if you have a WMI aware Asus machine and would like to use the
+	  firmware_attributes API to control various settings typically exposed in
+	  the ASUS Armoury Crate application available on Windows.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called asus-armoury.
+
 config ASUS_WMI
 	tristate "ASUS WMI Driver"
 	depends on ACPI_WMI
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index e1b142947067..fe3e7e7dede8 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX)	+= apple-gmux.o
 # ASUS
 obj-$(CONFIG_ASUS_LAPTOP)	+= asus-laptop.o
 obj-$(CONFIG_ASUS_WIRELESS)	+= asus-wireless.o
+obj-$(CONFIG_ASUS_ARMOURY)	+= asus-armoury.o
 obj-$(CONFIG_ASUS_WMI)		+= asus-wmi.o
 obj-$(CONFIG_ASUS_NB_WMI)	+= asus-nb-wmi.o
 obj-$(CONFIG_ASUS_TF103C_DOCK)	+= asus-tf103c-dock.o
diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
new file mode 100644
index 000000000000..39e422b16b8e
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.c
@@ -0,0 +1,563 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes
+ * class to expose the various WMI functions that many gaming and some
+ * non-gaming ASUS laptops have available.
+ * These typically don't fit anywhere else in the sysfs such as under LED class,
+ * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool.
+ *
+ * Copyright(C) 2010 Intel Corporation.
+ * Copyright(C) 2024-2024 Luke Jones <luke@ljones.dev>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/dmi.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/x86/asus-wmi.h>
+#include <linux/types.h>
+
+#include "asus-armoury.h"
+#include "firmware_attributes_class.h"
+#include "asus-wmi.h"
+
+#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
+
+#define ASUS_MINI_LED_MODE_MASK 0x03
+/* Standard modes for devices with only on/off */
+#define ASUS_MINI_LED_OFF 0x00
+#define ASUS_MINI_LED_ON 0x01
+/* Like "on" but the effect is more vibrant or brighter */
+#define ASUS_MINI_LED_STRONG_MODE 0x02
+/* New modes for devices with 3 mini-led mode types */
+#define ASUS_MINI_LED_2024_WEAK 0x00
+#define ASUS_MINI_LED_2024_STRONG 0x01
+#define ASUS_MINI_LED_2024_OFF 0x02
+
+/* Default limits for tunables available on ASUS ROG laptops */
+#define PPT_CPU_LIMIT_MIN 5
+#define PPT_CPU_LIMIT_MAX 150
+#define PPT_CPU_LIMIT_DEFAULT 80
+#define PPT_PLATFORM_MIN 5
+#define PPT_PLATFORM_MAX 100
+#define PPT_PLATFORM_DEFAULT 80
+#define NVIDIA_BOOST_MIN 5
+#define NVIDIA_BOOST_MAX 25
+#define NVIDIA_TEMP_MIN 75
+#define NVIDIA_TEMP_MAX 87
+
+static const struct class *fw_attr_class;
+
+struct asus_armoury_priv {
+	struct device *fw_attr_dev;
+	struct kset *fw_attr_kset;
+
+	u32 mini_led_dev_id;
+	u32 gpu_mux_dev_id;
+
+	struct mutex mutex;
+};
+
+static struct asus_armoury_priv asus_armoury = { .mutex = __MUTEX_INITIALIZER(
+							 asus_armoury.mutex) };
+
+struct fw_attrs_group {
+	bool pending_reboot;
+};
+
+static struct fw_attrs_group fw_attrs = {
+	.pending_reboot = false,
+};
+
+struct asus_attr_group {
+	const struct attribute_group *attr_group;
+	u32 wmi_devid;
+};
+
+static bool asus_wmi_is_present(u32 dev_id)
+{
+	u32 retval;
+	int status;
+
+	status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval);
+	pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
+
+	return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
+}
+
+static void asus_set_reboot_and_signal_event(void)
+{
+	fw_attrs.pending_reboot = true;
+	kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE);
+}
+
+static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+	return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot);
+}
+
+static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
+
+static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
+{
+	return !strcmp(attr->attr.name, "gpu_mux_mode");
+}
+
+/**
+ * attr_int_store() - Generic store function for use with most WMI functions.
+ * @kobj: Pointer to the driver object.
+ * @kobj_attribute: Pointer to the attribute calling this function.
+ * @buf: The buffer to read from, this is parsed to `int` type.
+ * @count:
+ * @min: Minimum accepted value. Below this returns -EINVAL.
+ * @max: Maximum accepted value. Above this returns -EINVAL.
+ * @store_value: Pointer to where the parsed value should be stored.
+ * @wmi_dev: The WMI function ID to use.
+ *
+ * The WMI functions available on most ASUS laptops return a 1 as "success", and
+ * a 0 as failed. However some functions can return n > 1 for additional errors.
+ * attr_int_store() currently treats all values which are not 1 as errors, ignoring
+ * the possible differences in WMI error returns.
+ *
+ * Returns: Either count, or an error.
+ */
+static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
+			      size_t count, u32 min, u32 max, u32 *store_value, u32 wmi_dev)
+{
+	u32 result, value;
+	int err;
+
+	err = kstrtouint(buf, 10, &value);
+	if (err)
+		return err;
+
+	if (value < min || value > max)
+		return -EINVAL;
+
+	err = asus_wmi_set_devstate(wmi_dev, value, &result);
+	if (err) {
+		pr_err("Failed to set %s: %d\n", attr->attr.name, err);
+		return err;
+	}
+
+	if (result != 1) {
+		pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result);
+		return -EIO;
+	}
+
+	if (store_value != NULL)
+		*store_value = value;
+	sysfs_notify(kobj, NULL, attr->attr.name);
+
+	if (asus_bios_requires_reboot(attr))
+		asus_set_reboot_and_signal_event();
+
+	return count;
+}
+
+/* Mini-LED mode **************************************************************/
+static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
+						struct kobj_attribute *attr, char *buf)
+{
+	u32 value;
+	int err;
+
+	err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value);
+	if (err)
+		return err;
+
+	value &= ASUS_MINI_LED_MODE_MASK;
+
+	/*
+	 * Remap the mode values to match previous generation mini-LED. The last gen
+	 * WMI 0 == off, while on this version WMI 2 == off (flipped).
+	 */
+	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
+		switch (value) {
+		case ASUS_MINI_LED_2024_WEAK:
+			value = ASUS_MINI_LED_ON;
+			break;
+		case ASUS_MINI_LED_2024_STRONG:
+			value = ASUS_MINI_LED_STRONG_MODE;
+			break;
+		case ASUS_MINI_LED_2024_OFF:
+			value = ASUS_MINI_LED_OFF;
+			break;
+		}
+	}
+
+	return sysfs_emit(buf, "%u\n", value);
+}
+
+static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
+						 struct kobj_attribute *attr, const char *buf,
+						 size_t count)
+{
+	int result, err;
+	u32 mode;
+
+	err = kstrtou32(buf, 10, &mode);
+	if (err)
+		return err;
+
+	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
+	    mode > ASUS_MINI_LED_ON)
+		return -EINVAL;
+	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
+	    mode > ASUS_MINI_LED_STRONG_MODE)
+		return -EINVAL;
+
+	/*
+	 * Remap the mode values so expected behaviour is the same as the last
+	 * generation of mini-LED with 0 == off, 1 == on.
+	 */
+	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
+		switch (mode) {
+		case ASUS_MINI_LED_OFF:
+			mode = ASUS_MINI_LED_2024_OFF;
+			break;
+		case ASUS_MINI_LED_ON:
+			mode = ASUS_MINI_LED_2024_WEAK;
+			break;
+		case ASUS_MINI_LED_STRONG_MODE:
+			mode = ASUS_MINI_LED_2024_STRONG;
+			break;
+		}
+	}
+
+	err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result);
+	if (err) {
+		pr_warn("Failed to set mini-LED: %d\n", err);
+		return err;
+	}
+
+	if (result != 1) {
+		pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(kobj, NULL, attr->attr.name);
+
+	return count;
+}
+
+static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
+						  struct kobj_attribute *attr, char *buf)
+{
+	switch (asus_armoury.mini_led_dev_id) {
+	case ASUS_WMI_DEVID_MINI_LED_MODE:
+		return sysfs_emit(buf, "0;1\n");
+	case ASUS_WMI_DEVID_MINI_LED_MODE2:
+		return sysfs_emit(buf, "0;1;2\n");
+	}
+
+	return sysfs_emit(buf, "0\n");
+}
+
+ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode");
+
+static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj,
+						struct kobj_attribute *attr, const char *buf,
+						size_t count)
+{
+	int result, err;
+	u32 optimus;
+
+	err = kstrtou32(buf, 10, &optimus);
+	if (err)
+		return err;
+
+	if (optimus > 1)
+		return -EINVAL;
+
+	if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) {
+		err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result);
+		if (err)
+			return err;
+		if (result && !optimus) {
+			err = -ENODEV;
+			pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %02X %02X %d\n",
+				result, optimus, err);
+			return err;
+		}
+	}
+
+	if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) {
+		err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result);
+		if (err)
+			return err;
+		if (result && !optimus) {
+			err = -ENODEV;
+			pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n",
+				err);
+			return err;
+		}
+	}
+
+	err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result);
+	if (err) {
+		pr_err("Failed to set GPU MUX mode: %d\n", err);
+		return err;
+	}
+	/* !1 is considered a fail by ASUS */
+	if (result != 1) {
+		pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(kobj, NULL, attr->attr.name);
+	asus_set_reboot_and_signal_event();
+
+	return count;
+}
+WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id);
+ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode");
+
+/*
+ * A user may be required to store the value twice, typical store first, then
+ * rescan PCI bus to activate power, then store a second time to save correctly.
+ * The reason for this is that an extra code path in the ACPI is enabled when
+ * the device and bus are powered.
+ */
+static ssize_t dgpu_disable_current_value_store(struct kobject *kobj,
+						struct kobj_attribute *attr, const char *buf,
+						size_t count)
+{
+	int result, err;
+	u32 disable;
+
+	err = kstrtou32(buf, 10, &disable);
+	if (err)
+		return err;
+
+	if (disable > 1)
+		return -EINVAL;
+
+	if (asus_armoury.gpu_mux_dev_id) {
+		err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
+		if (err)
+			return err;
+		if (!result && disable) {
+			err = -ENODEV;
+			pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
+			return err;
+		}
+	}
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
+	if (err) {
+		pr_warn("Failed to set dGPU disable: %d\n", err);
+		return err;
+	}
+
+	if (result != 1) {
+		pr_warn("Failed to set dGPU disable (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(kobj, NULL, attr->attr.name);
+
+	return count;
+}
+WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU);
+ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU");
+
+/* The ACPI call to enable the eGPU also disables the internal dGPU */
+static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
+					       const char *buf, size_t count)
+{
+	int result, err;
+	u32 enable;
+
+	err = kstrtou32(buf, 10, &enable);
+	if (err)
+		return err;
+
+	if (enable > 1)
+		return -EINVAL;
+
+	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result);
+	if (err) {
+		pr_warn("Failed to get eGPU connection status: %d\n", err);
+		return err;
+	}
+
+	if (asus_armoury.gpu_mux_dev_id) {
+		err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
+		if (err) {
+			pr_warn("Failed to get GPU MUX status: %d\n", result);
+			return result;
+		}
+		if (!result && enable) {
+			err = -ENODEV;
+			pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
+			return err;
+		}
+	}
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
+	if (err) {
+		pr_warn("Failed to set eGPU state: %d\n", err);
+		return err;
+	}
+
+	if (result != 1) {
+		pr_warn("Failed to set eGPU state (retval): 0x%x\n", result);
+		return -EIO;
+	}
+
+	sysfs_notify(kobj, NULL, attr->attr.name);
+
+	return count;
+}
+WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
+ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
+
+/* Simple attribute creation */
+ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
+		       "Show the current mode of charging");
+
+ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND,
+		   "Set the boot POST sound");
+ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
+		   "Set MCU powersaving mode");
+ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
+		   "Set the panel refresh overdrive");
+ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
+		   "Show the eGPU connection status");
+
+/* If an attribute does not require any special case handling add it here */
+static const struct asus_attr_group armoury_attr_groups[] = {
+	{ &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED },
+	{ &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
+	{ &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
+
+	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
+	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
+	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
+	{ &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
+};
+
+static int asus_fw_attr_add(void)
+{
+	int err;
+
+	err = fw_attributes_class_get(&fw_attr_class);
+	if (err)
+		goto fail_class_created;
+
+	asus_armoury.fw_attr_dev =
+		device_create(fw_attr_class, NULL, MKDEV(0, 0), NULL, "%s", DRIVER_NAME);
+
+	if (IS_ERR(asus_armoury.fw_attr_dev)) {
+		err = PTR_ERR(asus_armoury.fw_attr_dev);
+		goto fail_class_created;
+	}
+
+	asus_armoury.fw_attr_kset =
+		kset_create_and_add("attributes", NULL, &asus_armoury.fw_attr_dev->kobj);
+	if (!asus_armoury.fw_attr_dev) {
+		err = -ENOMEM;
+		pr_debug("Failed to create and add attributes\n");
+		goto err_destroy_classdev;
+	}
+
+	err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
+	if (err) {
+		pr_warn("Failed to create sysfs level attributes\n");
+		goto fail_class_created;
+	}
+
+	err = 0;
+	asus_armoury.mini_led_dev_id = 0;
+	if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
+		asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
+		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+					 &mini_led_mode_attr_group);
+	} else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
+		asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
+		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+					 &mini_led_mode_attr_group);
+	}
+	if (err)
+		pr_warn("Failed to create sysfs-group for mini_led\n");
+
+	err = 0;
+	asus_armoury.gpu_mux_dev_id = 0;
+	if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) {
+		asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX;
+		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+					 &gpu_mux_mode_attr_group);
+	} else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) {
+		asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO;
+		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+					 &gpu_mux_mode_attr_group);
+	}
+	if (err)
+		pr_warn("Failed to create sysfs-group for gpu_mux\n");
+
+	for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) {
+		if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid))
+			continue;
+
+		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
+					 armoury_attr_groups[i].attr_group);
+		if (err)
+			pr_warn("Failed to create sysfs-group for %s\n",
+				armoury_attr_groups[i].attr_group->name);
+		else
+			pr_debug("Created sysfs-group for %s\n",
+				 armoury_attr_groups[i].attr_group->name);
+	}
+
+	return 0;
+
+err_destroy_classdev:
+	device_destroy(fw_attr_class, MKDEV(0, 0));
+
+fail_class_created:
+	fw_attributes_class_put();
+	return err;
+}
+
+/* Init / exit ****************************************************************/
+
+static int __init asus_fw_init(void)
+{
+	int err;
+
+	fw_attrs.pending_reboot = false;
+
+	err = asus_fw_attr_add();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void __exit asus_fw_exit(void)
+{
+	mutex_lock(&asus_armoury.mutex);
+
+	sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
+	kset_unregister(asus_armoury.fw_attr_kset);
+	device_destroy(fw_attr_class, MKDEV(0, 0));
+	fw_attributes_class_put();
+
+	mutex_unlock(&asus_armoury.mutex);
+}
+
+module_init(asus_fw_init);
+module_exit(asus_fw_exit);
+
+MODULE_IMPORT_NS(ASUS_WMI);
+MODULE_AUTHOR("Luke Jones <luke@ljones.dev>");
+MODULE_DESCRIPTION("ASUS BIOS Configuration Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID);
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
new file mode 100644
index 000000000000..b99fd136abf1
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.h
@@ -0,0 +1,146 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Definitions for kernel modules using asus-armoury driver
+ *
+ *  Copyright (c) 2024 Luke Jones <luke@ljones.dev>
+ */
+
+#ifndef _ASUS_BIOSCFG_H_
+#define _ASUS_BIOSCFG_H_
+
+#include <linux/types.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "asus-armoury"
+
+static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
+			      const char *buf, size_t count, u32 min, u32 max,
+			      u32 *store_value, u32 wmi_dev);
+
+static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+			      char *buf)
+{
+	return sysfs_emit(buf, "enumeration\n");
+}
+
+#define __ASUS_ATTR_RO(_func, _name)                                  \
+	{                                                             \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = _func##_##_name##_show,                       \
+	}
+
+#define __ASUS_ATTR_RO_AS(_name, _show)                               \
+	{                                                             \
+		.attr = { .name = __stringify(_name), .mode = 0444 }, \
+		.show = _show,                                        \
+	}
+
+#define __ASUS_ATTR_RW(_func, _name) \
+	__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
+
+#define __WMI_STORE_INT(_attr, _min, _max, _wmi)                          \
+	static ssize_t _attr##_store(struct kobject *kobj,                \
+				     struct kobj_attribute *attr,         \
+				     const char *buf, size_t count)       \
+	{                                                                 \
+		return attr_int_store(kobj, attr, buf, count, _min, _max, \
+				      NULL, _wmi);                        \
+	}
+
+#define WMI_SHOW_INT(_attr, _fmt, _wmi)                                     \
+	static ssize_t _attr##_show(struct kobject *kobj,                   \
+				    struct kobj_attribute *attr, char *buf) \
+	{                                                                   \
+		u32 result;                                                 \
+		int err;                                                    \
+		err = asus_wmi_get_devstate_dsts(_wmi, &result);            \
+		if (err)                                                    \
+			return err;                                         \
+		return sysfs_emit(buf, _fmt,                                \
+				  result & ~ASUS_WMI_DSTS_PRESENCE_BIT);    \
+	}
+
+/* Create functions and attributes for use in other macros or on their own */
+
+#define __ATTR_CURRENT_INT_RO(_attr, _wmi)                          \
+	WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
+	static struct kobj_attribute attr_##_attr##_current_value = \
+		__ASUS_ATTR_RO(_attr, current_value)
+
+#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi)            \
+	__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \
+	WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
+	static struct kobj_attribute attr_##_attr##_current_value = \
+		__ASUS_ATTR_RW(_attr, current_value)
+
+/* Shows a formatted static variable */
+#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                         \
+	static ssize_t _attrname##_##_prop##_show(                            \
+		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+	{                                                                     \
+		return sysfs_emit(buf, _fmt, _val);                           \
+	}                                                                     \
+	static struct kobj_attribute attr_##_attrname##_##_prop =             \
+		__ASUS_ATTR_RO(_attrname, _prop)
+
+/* Boolean style enumeration, base macro. Requires adding show/store */
+#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)     \
+	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
+	__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
+	static struct kobj_attribute attr_##_attrname##_type =          \
+		__ASUS_ATTR_RO_AS(type, enum_type_show);                \
+	static struct attribute *_attrname##_attrs[] = {                \
+		&attr_##_attrname##_current_value.attr,                 \
+		&attr_##_attrname##_display_name.attr,                  \
+		&attr_##_attrname##_possible_values.attr,               \
+		&attr_##_attrname##_type.attr,                          \
+		NULL                                                    \
+	};                                                              \
+	static const struct attribute_group _attrname##_attr_group = {  \
+		.name = _fsname, .attrs = _attrname##_attrs             \
+	}
+
+#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
+	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                 \
+	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
+
+#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \
+	__ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi);           \
+	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
+
+/*
+ * Requires <name>_current_value_show(), <name>_current_value_show()
+ */
+#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname)           \
+	static struct kobj_attribute attr_##_attrname##_current_value = \
+		__ASUS_ATTR_RW(_attrname, current_value);               \
+	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
+
+#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \
+	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                                \
+	__ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)
+
+/*
+ * Requires <name>_current_value_show(), <name>_current_value_show()
+ * and <name>_possible_values_show()
+ */
+#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname)             \
+	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);      \
+	static struct kobj_attribute attr_##_attrname##_current_value =   \
+		__ASUS_ATTR_RW(_attrname, current_value);                 \
+	static struct kobj_attribute attr_##_attrname##_possible_values = \
+		__ASUS_ATTR_RO(_attrname, possible_values);               \
+	static struct kobj_attribute attr_##_attrname##_type =            \
+		__ASUS_ATTR_RO_AS(type, enum_type_show);                  \
+	static struct attribute *_attrname##_attrs[] = {                  \
+		&attr_##_attrname##_current_value.attr,                   \
+		&attr_##_attrname##_display_name.attr,                    \
+		&attr_##_attrname##_possible_values.attr,                 \
+		&attr_##_attrname##_type.attr,                            \
+		NULL                                                      \
+	};                                                                \
+	static const struct attribute_group _attrname##_attr_group = {    \
+		.name = _fsname, .attrs = _attrname##_attrs               \
+	}
+
+#endif /* _ASUS_BIOSCFG_H_ */
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (2 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:17   ` Mario Limonciello
  2024-09-26  9:29 ` [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs Luke D. Jones
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

Add panel_hd_mode to toggle the panel mode between single and high
definition modes.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-armoury.c        | 6 +++++-
 include/linux/platform_data/x86/asus-wmi.h | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index 39e422b16b8e..15eab4d45b81 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -106,7 +106,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
 
 static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
 {
-	return !strcmp(attr->attr.name, "gpu_mux_mode");
+	return !strcmp(attr->attr.name, "gpu_mux_mode") ||
+	       !strcmp(attr->attr.name, "panel_hd_mode");
 }
 
 /**
@@ -429,6 +430,8 @@ ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
 		   "Set MCU powersaving mode");
 ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
 		   "Set the panel refresh overdrive");
+ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD,
+		   "Set the panel HD mode to UHD<0> or FHD<1>");
 ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
 		   "Show the eGPU connection status");
 
@@ -442,6 +445,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
 	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
 	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
 	{ &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
+	{ &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD },
 };
 
 static int asus_fw_attr_add(void)
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 6ea4dedfb85e..7caf2c7ed8c9 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -73,6 +73,7 @@
 #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
 
 /* Misc */
+#define ASUS_WMI_DEVID_PANEL_HD		0x0005001C
 #define ASUS_WMI_DEVID_PANEL_OD		0x00050019
 #define ASUS_WMI_DEVID_CAMERA		0x00060013
 #define ASUS_WMI_DEVID_LID_FLIP		0x00060062
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (3 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:22   ` Mario Limonciello
  2024-09-26  9:29 ` [PATCH v4 6/9] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

Adds the ppt_* and nv_* tuning knobs that are available via WMI methods
and adds proper min/max levels plus defaults.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-armoury.c | 130 ++++++++++++++++++++++++++++
 drivers/platform/x86/asus-armoury.h |  65 ++++++++++++++
 2 files changed, 195 insertions(+)

diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index 15eab4d45b81..766f944d0233 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -52,12 +52,40 @@
 #define NVIDIA_TEMP_MIN 75
 #define NVIDIA_TEMP_MAX 87
 
+/* Tunables provided by ASUS for gaming laptops */
+struct rog_tunables {
+	u32 cpu_default;
+	u32 cpu_min;
+	u32 cpu_max;
+
+	u32 platform_default;
+	u32 platform_min;
+	u32 platform_max;
+
+	u32 ppt_pl1_spl; // cpu
+	u32 ppt_pl2_sppt; // cpu
+	u32 ppt_apu_sppt; // plat
+	u32 ppt_platform_sppt; // plat
+	u32 ppt_fppt; // cpu
+
+	u32 nv_boost_default;
+	u32 nv_boost_min;
+	u32 nv_boost_max;
+	u32 nv_dynamic_boost;
+
+	u32 nv_temp_default;
+	u32 nv_temp_min;
+	u32 nv_temp_max;
+	u32 nv_temp_target;
+};
+
 static const struct class *fw_attr_class;
 
 struct asus_armoury_priv {
 	struct device *fw_attr_dev;
 	struct kset *fw_attr_kset;
 
+	struct rog_tunables *rog_tunables;
 	u32 mini_led_dev_id;
 	u32 gpu_mux_dev_id;
 
@@ -421,6 +449,25 @@ WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
 ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
 
 /* Simple attribute creation */
+ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
+		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
+ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, cpu_default,
+		       cpu_min, cpu_max, 1, "Set the CPU fast package limit");
+ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT,
+		       platform_default, platform_min, platform_max, 1,
+		       "Set the CPU slow package limit");
+ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT,
+		       platform_default, platform_min, platform_max, 1,
+		       "Set the CPU slow package limit");
+ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, cpu_default, cpu_min,
+		       cpu_max, 1, "Set the CPU slow package limit");
+ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST,
+		       nv_boost_default, nv_boost_min, nv_boost_max, 1,
+		       "Set the Nvidia dynamic boost limit");
+ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET,
+		       nv_temp_default, nv_boost_min, nv_temp_max, 1,
+		       "Set the Nvidia max thermal limit");
+
 ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
 		       "Show the current mode of charging");
 
@@ -441,6 +488,14 @@ static const struct asus_attr_group armoury_attr_groups[] = {
 	{ &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
 	{ &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
 
+	{ &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL },
+	{ &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT },
+	{ &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT },
+	{ &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT },
+	{ &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT },
+	{ &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
+	{ &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
+
 	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
 	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
 	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
@@ -532,12 +587,87 @@ static int asus_fw_attr_add(void)
 
 /* Init / exit ****************************************************************/
 
+/* Set up the min/max and defaults for ROG tunables */
+static void init_rog_tunables(struct rog_tunables *rog)
+{
+	const char *product;
+	u32 max_boost = NVIDIA_BOOST_MAX;
+	u32 cpu_default = PPT_CPU_LIMIT_DEFAULT;
+	u32 cpu_max = PPT_CPU_LIMIT_MAX;
+	u32 platform_default = PPT_PLATFORM_DEFAULT;
+	u32 platform_max = PPT_PLATFORM_MAX;
+
+	/*
+	 * ASUS product_name contains everything required, e.g,
+	 * "ROG Flow X16 GV601VV_GV601VV_00185149B"
+	 */
+	product = dmi_get_system_info(DMI_PRODUCT_NAME);
+
+	if (strstr(product, "GA402R")) {
+		cpu_default = 125;
+	} else if (strstr(product, "13QY")) {
+		cpu_max = 250;
+	} else if (strstr(product, "X13")) {
+		cpu_max = 75;
+		cpu_default = 50;
+	} else if (strstr(product, "RC71") || strstr(product, "RC72")) {
+		cpu_max = 50;
+		cpu_default = 30;
+	} else if (strstr(product, "G814") || strstr(product, "G614") ||
+		   strstr(product, "G834") || strstr(product, "G634")) {
+		cpu_max = 175;
+	} else if (strstr(product, "GA402X") || strstr(product, "GA403") ||
+		   strstr(product, "FA507N") || strstr(product, "FA507X") ||
+		   strstr(product, "FA707N") || strstr(product, "FA707X")) {
+		cpu_max = 90;
+	}
+
+	if (strstr(product, "GZ301ZE"))
+		max_boost = 5;
+	else if (strstr(product, "FX507ZC4"))
+		max_boost = 15;
+	else if (strstr(product, "GU605"))
+		max_boost = 20;
+
+	/* ensure defaults for tunables */
+	rog->cpu_default = cpu_default;
+	rog->cpu_min = PPT_CPU_LIMIT_MIN;
+	rog->cpu_max = cpu_max;
+
+	rog->platform_default = platform_default;
+	rog->platform_max = PPT_PLATFORM_MIN;
+	rog->platform_max = platform_max;
+
+	rog->ppt_pl1_spl = cpu_default;
+	rog->ppt_pl2_sppt = cpu_default;
+	rog->ppt_apu_sppt = cpu_default;
+
+	rog->ppt_platform_sppt = platform_default;
+	rog->ppt_fppt = cpu_default;
+
+	rog->nv_boost_default = NVIDIA_BOOST_MAX;
+	rog->nv_boost_max = NVIDIA_BOOST_MIN;
+	rog->nv_boost_max = max_boost;
+	rog->nv_dynamic_boost = NVIDIA_BOOST_MIN;
+
+	rog->nv_temp_default = NVIDIA_TEMP_MAX;
+	rog->nv_temp_max = NVIDIA_TEMP_MIN;
+	rog->nv_temp_max = NVIDIA_TEMP_MAX;
+	rog->nv_temp_target = NVIDIA_TEMP_MIN;
+}
+
 static int __init asus_fw_init(void)
 {
 	int err;
 
 	fw_attrs.pending_reboot = false;
 
+	asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL);
+	if (!asus_armoury.rog_tunables)
+		return -ENOMEM;
+
+	init_rog_tunables(asus_armoury.rog_tunables);
+
 	err = asus_fw_attr_add();
 	if (err)
 		return err;
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index b99fd136abf1..9e63ea0d9d44 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -17,6 +17,12 @@ static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
 			      const char *buf, size_t count, u32 min, u32 max,
 			      u32 *store_value, u32 wmi_dev);
 
+static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr,
+			     char *buf)
+{
+	return sysfs_emit(buf, "integer\n");
+}
+
 static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 			      char *buf)
 {
@@ -143,4 +149,63 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 		.name = _fsname, .attrs = _attrname##_attrs               \
 	}
 
+/*
+ * ROG PPT attributes need a little different in setup as they
+ * require rog_tunables members.
+ */
+
+#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi)                             \
+	static ssize_t _attr##_current_value_store(                           \
+		struct kobject *kobj, struct kobj_attribute *attr,            \
+		const char *buf, size_t count)                                \
+	{                                                                     \
+		return attr_int_store(kobj, attr, buf, count,                 \
+				      asus_armoury.rog_tunables->_min,        \
+				      asus_armoury.rog_tunables->_max,        \
+				      &asus_armoury.rog_tunables->_attr,      \
+				      _wmi);                                  \
+	}                                                                     \
+	static ssize_t _attr##_current_value_show(                            \
+		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+	{                                                                     \
+		return sysfs_emit(buf, "%u\n",                                \
+				  asus_armoury.rog_tunables->_attr);          \
+	}                                                                     \
+	static struct kobj_attribute attr_##_attr##_current_value =           \
+		__ASUS_ATTR_RW(_attr, current_value)
+
+#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val)                            \
+	static ssize_t _attrname##_##_prop##_show(                            \
+		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
+	{                                                                     \
+		return sysfs_emit(buf, "%d\n",                                \
+				  asus_armoury.rog_tunables->_val);           \
+	}                                                                     \
+	static struct kobj_attribute attr_##_attrname##_##_prop =             \
+		__ASUS_ATTR_RO(_attrname, _prop)
+
+#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, _min, _max, \
+			       _incstep, _dispname)                            \
+	__ROG_TUNABLE_SHOW(default_value, _attrname, _default);                \
+	__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi);                         \
+	__ROG_TUNABLE_SHOW(min_value, _attrname, _min);                        \
+	__ROG_TUNABLE_SHOW(max_value, _attrname, _max);                        \
+	__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep);        \
+	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);           \
+	static struct kobj_attribute attr_##_attrname##_type =                 \
+		__ASUS_ATTR_RO_AS(type, int_type_show);                        \
+	static struct attribute *_attrname##_attrs[] = {                       \
+		&attr_##_attrname##_current_value.attr,                        \
+		&attr_##_attrname##_default_value.attr,                        \
+		&attr_##_attrname##_min_value.attr,                            \
+		&attr_##_attrname##_max_value.attr,                            \
+		&attr_##_attrname##_scalar_increment.attr,                     \
+		&attr_##_attrname##_display_name.attr,                         \
+		&attr_##_attrname##_type.attr,                                 \
+		NULL                                                           \
+	};                                                                     \
+	static const struct attribute_group _attrname##_attr_group = {         \
+		.name = _fsname, .attrs = _attrname##_attrs                    \
+	}
+
 #endif /* _ASUS_BIOSCFG_H_ */
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 6/9] platform/x86: asus-armoury: add dgpu tgp control
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (4 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26  9:29 ` [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones,
	Mario Limonciello

Implement the dgpu TGP control under the asus-armoury module using the
fw_attributes class.

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-armoury.c        | 21 +++++++++++++++++++++
 drivers/platform/x86/asus-armoury.h        | 18 ++++++++++++++++++
 include/linux/platform_data/x86/asus-wmi.h |  3 +++
 3 files changed, 42 insertions(+)

diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index 766f944d0233..0f67b5deb629 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -51,6 +51,9 @@
 #define NVIDIA_BOOST_MAX 25
 #define NVIDIA_TEMP_MIN 75
 #define NVIDIA_TEMP_MAX 87
+#define NVIDIA_POWER_MIN 0
+#define NVIDIA_POWER_MAX 70
+#define NVIDIA_POWER_DEFAULT 70
 
 /* Tunables provided by ASUS for gaming laptops */
 struct rog_tunables {
@@ -77,6 +80,11 @@ struct rog_tunables {
 	u32 nv_temp_min;
 	u32 nv_temp_max;
 	u32 nv_temp_target;
+
+	u32 dgpu_tgp_default;
+	u32 dgpu_tgp_min;
+	u32 dgpu_tgp_max;
+	u32 dgpu_tgp;
 };
 
 static const struct class *fw_attr_class;
@@ -467,6 +475,12 @@ ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_D
 ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET,
 		       nv_temp_default, nv_boost_min, nv_temp_max, 1,
 		       "Set the Nvidia max thermal limit");
+ATTR_GROUP_ROG_TUNABLE(dgpu_tgp, "dgpu_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, dgpu_tgp_default,
+		       dgpu_tgp_min, dgpu_tgp_max, 1,
+		       "Set the additional TGP on top of the base TGP");
+
+ATTR_GROUP_INT_VALUE_ONLY_RO(dgpu_base_tgp, "dgpu_base_tgp", ASUS_WMI_DEVID_DGPU_BASE_TGP,
+			     "Read the base TGP value");
 
 ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
 		       "Show the current mode of charging");
@@ -495,6 +509,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
 	{ &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT },
 	{ &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
 	{ &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
+	{ &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
+	{ &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
 
 	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
 	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
@@ -654,6 +670,11 @@ static void init_rog_tunables(struct rog_tunables *rog)
 	rog->nv_temp_max = NVIDIA_TEMP_MIN;
 	rog->nv_temp_max = NVIDIA_TEMP_MAX;
 	rog->nv_temp_target = NVIDIA_TEMP_MIN;
+
+	rog->dgpu_tgp_default = NVIDIA_POWER_DEFAULT;
+	rog->dgpu_tgp_min = NVIDIA_POWER_MIN;
+	rog->dgpu_tgp_max = NVIDIA_POWER_MAX;
+	rog->dgpu_tgp = NVIDIA_POWER_MAX;
 }
 
 static int __init asus_fw_init(void)
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index 9e63ea0d9d44..a5f95e806b4b 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -89,6 +89,20 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 	static struct kobj_attribute attr_##_attrname##_##_prop =             \
 		__ASUS_ATTR_RO(_attrname, _prop)
 
+/* Requires current_value_show */
+#define __ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname)     \
+	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);   \
+	static struct kobj_attribute attr_##_attrname##_type =         \
+		__ASUS_ATTR_RO_AS(type, int_type_show);                \
+	static struct attribute *_attrname##_attrs[] = {               \
+		&attr_##_attrname##_current_value.attr,                \
+		&attr_##_attrname##_display_name.attr,                 \
+		&attr_##_attrname##_type.attr, NULL                    \
+	};                                                             \
+	static const struct attribute_group _attrname##_attr_group = { \
+		.name = _fsname, .attrs = _attrname##_attrs            \
+	}
+
 /* Boolean style enumeration, base macro. Requires adding show/store */
 #define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)     \
 	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
@@ -106,6 +120,10 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 		.name = _fsname, .attrs = _attrname##_attrs             \
 	}
 
+#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \
+	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                           \
+	__ATTR_GROUP_INT_VALUE_ONLY(_attrname, _fsname, _dispname)
+
 #define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
 	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                 \
 	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 7caf2c7ed8c9..86629e621c61 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -134,6 +134,9 @@
 /* dgpu on/off */
 #define ASUS_WMI_DEVID_DGPU		0x00090020
 
+#define ASUS_WMI_DEVID_DGPU_BASE_TGP	0x00120099
+#define ASUS_WMI_DEVID_DGPU_SET_TGP	0x00120098
+
 /* gpu mux switch, 0 = dGPU, 1 = Optimus */
 #define ASUS_WMI_DEVID_GPU_MUX		0x00090016
 #define ASUS_WMI_DEVID_GPU_MUX_VIVO	0x00090026
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (5 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 6/9] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:25   ` Mario Limonciello
  2024-09-26  9:29 ` [PATCH v4 8/9] platform/x86: asus-armoury: add core count control Luke D. Jones
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

Implement the APU memory size control under the asus-armoury module using
the fw_attributes class.

This allows the APU allocated memory size to be adjusted depending on
the users priority. A reboot is required after change.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-armoury.c        | 114 +++++++++++++++++++++
 include/linux/platform_data/x86/asus-wmi.h |   1 +
 2 files changed, 115 insertions(+)

diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index 0f67b5deb629..a0022dcee3a4 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -456,6 +456,119 @@ static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj
 WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
 ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
 
+/* Device memory available to APU */
+
+static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
+					  char *buf)
+{
+	int err;
+	u32 mem;
+
+	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem);
+	if (err)
+		return err;
+
+	switch (mem) {
+	case 0x100:
+		mem = 0;
+		break;
+	case 0x102:
+		mem = 1;
+		break;
+	case 0x103:
+		mem = 2;
+		break;
+	case 0x104:
+		mem = 3;
+		break;
+	case 0x105:
+		mem = 4;
+		break;
+	case 0x106:
+		/* This is out of order and looks wrong but is correct */
+		mem = 8;
+		break;
+	case 0x107:
+		mem = 5;
+		break;
+	case 0x108:
+		mem = 6;
+		break;
+	case 0x109:
+		mem = 7;
+		break;
+	default:
+		mem = 4;
+		break;
+	}
+
+	return sysfs_emit(buf, "%u\n", mem);
+}
+
+static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
+					   const char *buf, size_t count)
+{
+	int result, err;
+	u32 requested, mem;
+
+	result = kstrtou32(buf, 10, &requested);
+	if (result)
+		return result;
+
+	switch (requested) {
+	case 0:
+		mem = 0x000;
+		break;
+	case 1:
+		mem = 0x102;
+		break;
+	case 2:
+		mem = 0x103;
+		break;
+	case 3:
+		mem = 0x104;
+		break;
+	case 4:
+		mem = 0x105;
+		break;
+	case 5:
+		mem = 0x107;
+		break;
+	case 6:
+		mem = 0x108;
+		break;
+	case 7:
+		mem = 0x109;
+		break;
+	case 8:
+		/* This is out of order and looks wrong but is correct */
+		mem = 0x106;
+		break;
+	default:
+		return -EIO;
+	}
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result);
+	if (err) {
+		pr_warn("Failed to set apu_mem: %d\n", err);
+		return err;
+	}
+
+	pr_info("APU memory changed to %uGB, reboot required\n", requested);
+	sysfs_notify(kobj, NULL, attr->attr.name);
+
+	asus_set_reboot_and_signal_event();
+
+	return count;
+}
+
+static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr,
+					    char *buf)
+{
+	return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n");
+}
+ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
+
 /* Simple attribute creation */
 ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
 		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
@@ -511,6 +624,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
 	{ &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
 	{ &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
 	{ &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
+	{ &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
 
 	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
 	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 86629e621c61..e1aeafdf05d5 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -136,6 +136,7 @@
 
 #define ASUS_WMI_DEVID_DGPU_BASE_TGP	0x00120099
 #define ASUS_WMI_DEVID_DGPU_SET_TGP	0x00120098
+#define ASUS_WMI_DEVID_APU_MEM		0x000600C1
 
 /* gpu mux switch, 0 = dGPU, 1 = Optimus */
 #define ASUS_WMI_DEVID_GPU_MUX		0x00090016
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 8/9] platform/x86: asus-armoury: add core count control
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (6 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 15:30   ` Mario Limonciello
  2024-09-26  9:29 ` [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
  2024-09-26 14:50 ` [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Mario Limonciello
  9 siblings, 1 reply; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

Implement Intel core enablement under the asus-armoury module using the
fw_attributes class.

This allows users to enable or disable preformance or efficiency cores
depending on their requirements. After change a reboot is required.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 drivers/platform/x86/asus-armoury.c        | 219 +++++++++++++++++++++
 drivers/platform/x86/asus-armoury.h        |  28 +++
 include/linux/platform_data/x86/asus-wmi.h |   4 +
 3 files changed, 251 insertions(+)

diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
index a0022dcee3a4..ce1facb40bd5 100644
--- a/drivers/platform/x86/asus-armoury.c
+++ b/drivers/platform/x86/asus-armoury.c
@@ -40,6 +40,21 @@
 #define ASUS_MINI_LED_2024_STRONG 0x01
 #define ASUS_MINI_LED_2024_OFF 0x02
 
+#define ASUS_POWER_CORE_MASK GENMASK(15, 8)
+#define ASUS_PERF_CORE_MASK GENMASK(7, 0)
+
+enum cpu_core_type {
+	CPU_CORE_PERF = 0,
+	CPU_CORE_POWER,
+};
+
+enum cpu_core_value {
+	CPU_CORE_DEFAULT = 0,
+	CPU_CORE_MIN,
+	CPU_CORE_MAX,
+	CPU_CORE_CURRENT,
+};
+
 /* Default limits for tunables available on ASUS ROG laptops */
 #define PPT_CPU_LIMIT_MIN 5
 #define PPT_CPU_LIMIT_MAX 150
@@ -85,6 +100,13 @@ struct rog_tunables {
 	u32 dgpu_tgp_min;
 	u32 dgpu_tgp_max;
 	u32 dgpu_tgp;
+
+	u32 cur_perf_cores;
+	u32 min_perf_cores;
+	u32 max_perf_cores;
+	u32 cur_power_cores;
+	u32 min_power_cores;
+	u32 max_power_cores;
 };
 
 static const struct class *fw_attr_class;
@@ -143,6 +165,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
 static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
 {
 	return !strcmp(attr->attr.name, "gpu_mux_mode") ||
+	       !strcmp(attr->attr.name, "cores_performance") ||
+	       !strcmp(attr->attr.name, "cores_efficiency") ||
 	       !strcmp(attr->attr.name, "panel_hd_mode");
 }
 
@@ -569,6 +593,198 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at
 }
 ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
 
+static int init_max_cpu_cores(void)
+{
+	u32 cores;
+	int err;
+
+	asus_armoury.rog_tunables->min_perf_cores = 4;
+	asus_armoury.rog_tunables->max_perf_cores = 4;
+	asus_armoury.rog_tunables->cur_perf_cores = 4;
+	asus_armoury.rog_tunables->min_power_cores = 0;
+	asus_armoury.rog_tunables->max_power_cores = 8;
+	asus_armoury.rog_tunables->cur_power_cores = 8;
+
+	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
+	if (err)
+		return err;
+
+	cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
+	asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
+	asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
+
+	cores = 0;
+	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
+	if (err)
+		return err;
+
+	asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
+	asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
+
+	return 0;
+}
+
+static ssize_t cores_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf,
+				enum cpu_core_type core_type, enum cpu_core_value core_value)
+{
+	u32 cores;
+
+	switch (core_value) {
+	case CPU_CORE_DEFAULT:
+	case CPU_CORE_MAX:
+		if (core_type == CPU_CORE_PERF)
+			return sysfs_emit(buf, "%d\n",
+					  asus_armoury.rog_tunables->max_perf_cores);
+		else
+			return sysfs_emit(buf, "%d\n",
+					  asus_armoury.rog_tunables->max_power_cores);
+	case CPU_CORE_MIN:
+		if (core_type == CPU_CORE_PERF)
+			return sysfs_emit(buf, "%d\n",
+					  asus_armoury.rog_tunables->min_perf_cores);
+		else
+			return sysfs_emit(buf, "%d\n",
+					  asus_armoury.rog_tunables->min_power_cores);
+	default:
+		break;
+	}
+
+	if (core_type == CPU_CORE_PERF)
+		cores = asus_armoury.rog_tunables->cur_perf_cores;
+	else
+		cores = asus_armoury.rog_tunables->cur_power_cores;
+
+	return sysfs_emit(buf, "%d\n", cores);
+}
+
+static ssize_t cores_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
+					 const char *buf, enum cpu_core_type core_type)
+{
+	int result, err;
+	u32 new_cores, perf_cores, powr_cores, out_val, min, max;
+
+	result = kstrtou32(buf, 10, &new_cores);
+	if (result)
+		return result;
+
+	if (core_type == CPU_CORE_PERF) {
+		perf_cores = new_cores;
+		powr_cores = out_val = asus_armoury.rog_tunables->cur_power_cores;
+		min = asus_armoury.rog_tunables->min_perf_cores;
+		max = asus_armoury.rog_tunables->max_perf_cores;
+	} else {
+		perf_cores = asus_armoury.rog_tunables->cur_perf_cores;
+		powr_cores = out_val = new_cores;
+		min = asus_armoury.rog_tunables->min_power_cores;
+		max = asus_armoury.rog_tunables->max_power_cores;
+	}
+
+	if (new_cores < min || new_cores > max)
+		return -EINVAL;
+
+	out_val = 0;
+	out_val |= FIELD_PREP(ASUS_PERF_CORE_MASK, perf_cores);
+	out_val |= FIELD_PREP(ASUS_POWER_CORE_MASK, powr_cores);
+
+	mutex_lock(&asus_armoury.mutex);
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, out_val, &result);
+	mutex_unlock(&asus_armoury.mutex);
+
+	if (err) {
+		pr_warn("Failed to set CPU core count: %d\n", err);
+		return err;
+	}
+
+	if (result > 1) {
+		pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
+		return -EIO;
+	}
+
+	pr_info("CPU core count changed, reboot required\n");
+	sysfs_notify(kobj, NULL, attr->attr.name);
+	asus_set_reboot_and_signal_event();
+
+	return 0;
+}
+
+static ssize_t cores_performance_min_value_show(struct kobject *kobj,
+						struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
+}
+
+static ssize_t cores_performance_max_value_show(struct kobject *kobj,
+						struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
+}
+
+static ssize_t cores_performance_default_value_show(struct kobject *kobj,
+						    struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
+}
+
+static ssize_t cores_performance_current_value_show(struct kobject *kobj,
+						    struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
+}
+
+static ssize_t cores_performance_current_value_store(struct kobject *kobj,
+						     struct kobj_attribute *attr,
+						     const char *buf, size_t count)
+{
+	int err;
+
+	err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
+	if (err)
+		return err;
+
+	return count;
+}
+ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
+		    "Set the max available performance cores");
+
+static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
+					       char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
+}
+
+static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
+					       char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
+}
+
+static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
+						   struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
+}
+
+static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
+						   struct kobj_attribute *attr, char *buf)
+{
+	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
+}
+
+static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
+						    struct kobj_attribute *attr, const char *buf,
+						    size_t count)
+{
+	int err;
+
+	err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
+	if (err)
+		return err;
+
+	return count;
+}
+ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
+		    "Set the max available efficiency cores");
+
 /* Simple attribute creation */
 ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
 		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
@@ -625,6 +841,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
 	{ &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
 	{ &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
 	{ &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
+	{ &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
+	{ &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
 
 	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
 	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
@@ -802,6 +1020,7 @@ static int __init asus_fw_init(void)
 		return -ENOMEM;
 
 	init_rog_tunables(asus_armoury.rog_tunables);
+	init_max_cpu_cores();
 
 	err = asus_fw_attr_add();
 	if (err)
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index a5f95e806b4b..f400e3af24be 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -167,6 +167,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
 		.name = _fsname, .attrs = _attrname##_attrs               \
 	}
 
+/* CPU core attributes need a little different in setup */
+#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname)              \
+	__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1);        \
+	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
+	static struct kobj_attribute attr_##_attrname##_current_value = \
+		__ASUS_ATTR_RW(_attrname, current_value);               \
+	static struct kobj_attribute attr_##_attrname##_default_value = \
+		__ASUS_ATTR_RO(_attrname, default_value);               \
+	static struct kobj_attribute attr_##_attrname##_min_value =     \
+		__ASUS_ATTR_RO(_attrname, min_value);                   \
+	static struct kobj_attribute attr_##_attrname##_max_value =     \
+		__ASUS_ATTR_RO(_attrname, max_value);                   \
+	static struct kobj_attribute attr_##_attrname##_type =          \
+		__ASUS_ATTR_RO_AS(type, int_type_show);                 \
+	static struct attribute *_attrname##_attrs[] = {                \
+		&attr_##_attrname##_current_value.attr,                 \
+		&attr_##_attrname##_default_value.attr,                 \
+		&attr_##_attrname##_min_value.attr,                     \
+		&attr_##_attrname##_max_value.attr,                     \
+		&attr_##_attrname##_scalar_increment.attr,              \
+		&attr_##_attrname##_display_name.attr,                  \
+		&attr_##_attrname##_type.attr,                          \
+		NULL                                                    \
+	};                                                              \
+	static const struct attribute_group _attrname##_attr_group = {  \
+		.name = _fsname, .attrs = _attrname##_attrs             \
+	}
+
 /*
  * ROG PPT attributes need a little different in setup as they
  * require rog_tunables members.
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index e1aeafdf05d5..8964e601543a 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -134,6 +134,10 @@
 /* dgpu on/off */
 #define ASUS_WMI_DEVID_DGPU		0x00090020
 
+/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
+#define ASUS_WMI_DEVID_CORES		0x001200D2
+ /* Maximum Intel E-core and P-core availability */
+#define ASUS_WMI_DEVID_CORES_MAX	0x001200D3
 #define ASUS_WMI_DEVID_DGPU_BASE_TGP	0x00120099
 #define ASUS_WMI_DEVID_DGPU_SET_TGP	0x00120098
 #define ASUS_WMI_DEVID_APU_MEM		0x000600C1
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (7 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 8/9] platform/x86: asus-armoury: add core count control Luke D. Jones
@ 2024-09-26  9:29 ` Luke D. Jones
  2024-09-26 14:56   ` Mario Limonciello
  2024-09-28  0:13   ` kernel test robot
  2024-09-26 14:50 ` [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Mario Limonciello
  9 siblings, 2 replies; 39+ messages in thread
From: Luke D. Jones @ 2024-09-26  9:29 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary, superm1, Luke D. Jones

With the existence of the asus-bioscfg module the attributes no-longer
need to live under the /sys/devices/platform/asus-nb-wmi/ path.

Deprecate all those that were implemented in asus-bioscfg with the goal
of removing them fully in the next LTS cycle.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 .../ABI/testing/sysfs-platform-asus-wmi       |  17 +++
 drivers/platform/x86/Kconfig                  |   9 ++
 drivers/platform/x86/asus-wmi.c               | 134 ++++++++++++++----
 3 files changed, 130 insertions(+), 30 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 28144371a0f1..765d50b0d9df 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -63,6 +63,7 @@ Date:		Aug 2022
 KernelVersion:	6.1
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Switch the GPU hardware MUX mode. Laptops with this feature can
 		can be toggled to boot with only the dGPU (discrete mode) or in
 		standard Optimus/Hybrid mode. On switch a reboot is required:
@@ -75,6 +76,7 @@ Date:		Aug 2022
 KernelVersion:	5.17
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Disable discrete GPU:
 			* 0 - Enable dGPU,
 			* 1 - Disable dGPU
@@ -84,6 +86,7 @@ Date:		Aug 2022
 KernelVersion:	5.17
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Enable the external GPU paired with ROG X-Flow laptops.
 		Toggling this setting will also trigger ACPI to disable the dGPU:
 
@@ -95,6 +98,7 @@ Date:		Aug 2022
 KernelVersion:	5.17
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Enable an LCD response-time boost to reduce or remove ghosting:
 			* 0 - Disable,
 			* 1 - Enable
@@ -104,6 +108,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Get the current charging mode being used:
 			* 1 - Barrel connected charger,
 			* 2 - USB-C charging
@@ -114,6 +119,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Show if the egpu (XG Mobile) is correctly connected:
 			* 0 - False,
 			* 1 - True
@@ -123,6 +129,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Change the mini-LED mode:
 			* 0 - Single-zone,
 			* 1 - Multi-zone
@@ -133,6 +140,7 @@ Date:		Apr 2024
 KernelVersion:	6.10
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		List the available mini-led modes.
 
 What:		/sys/devices/platform/<platform>/ppt_pl1_spl
@@ -140,6 +148,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
 		Shown on Intel+Nvidia or AMD+Nvidia based systems:
 
@@ -150,6 +159,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
 		on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
 
@@ -160,6 +170,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
 			* min=5, max=250
 
@@ -168,6 +179,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the APU SPPT limit. Shown on full AMD systems only:
 			* min=5, max=130
 
@@ -176,6 +188,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the platform SPPT limit. Shown on full AMD systems only:
 			* min=5, max=130
 
@@ -184,6 +197,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the dynamic boost limit of the Nvidia dGPU:
 			* min=5, max=25
 
@@ -192,6 +206,7 @@ Date:		Jun 2023
 KernelVersion:	6.5
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set the target temperature limit of the Nvidia dGPU:
 			* min=75, max=87
 
@@ -200,6 +215,7 @@ Date:		Apr 2024
 KernelVersion:	6.10
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set if the BIOS POST sound is played on boot.
 			* 0 - False,
 			* 1 - True
@@ -209,6 +225,7 @@ Date:		Apr 2024
 KernelVersion:	6.10
 Contact:	"Luke Jones" <luke@ljones.dev>
 Description:
+        DEPRECATED, WILL BE REMOVED SOON
 		Set if the MCU can go in to low-power mode on system sleep
 			* 0 - False,
 			* 1 - True
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index dedf66e0d099..baa36413f6ed 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -300,6 +300,15 @@ config ASUS_WMI
 	  To compile this driver as a module, choose M here: the module will
 	  be called asus-wmi.
 
+config ASUS_WMI_DEPRECATED_ATTRS
+	bool "BIOS option support in WMI platform (DEPRECATED)"
+	depends on ASUS_WMI
+	default y
+	help
+	  Say Y to expose the configurable BIOS options through the asus-wmi
+	  driver. This can be used with or without the new asus-armoury driver which
+	  hasthe same attributes, but more, and better features.
+
 config ASUS_NB_WMI
 	tristate "Asus Notebook WMI Driver"
 	depends on ASUS_WMI
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 0a5221d65130..f553c0b33da7 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -289,11 +289,12 @@ struct asus_wmi {
 	u8 fan_boost_mode_mask;
 	u8 fan_boost_mode;
 
+
+	/* Tunables provided by ASUS for gaming laptops */
+	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 	bool egpu_enable_available;
 	bool dgpu_disable_available;
 	u32 gpu_mux_dev;
-
-	/* Tunables provided by ASUS for gaming laptops */
 	u32 ppt_pl2_sppt;
 	u32 ppt_pl1_spl;
 	u32 ppt_apu_sppt;
@@ -301,6 +302,9 @@ struct asus_wmi {
 	u32 ppt_fppt;
 	u32 nv_dynamic_boost;
 	u32 nv_temp_target;
+	bool panel_overdrive_available;
+	u32 mini_led_dev_id;
+	#endif
 
 	u32 kbd_rgb_dev;
 	bool kbd_rgb_state_available;
@@ -319,9 +323,6 @@ struct asus_wmi {
 	// The RSOC controls the maximum charging percentage.
 	bool battery_rsoc_available;
 
-	bool panel_overdrive_available;
-	u32 mini_led_dev_id;
-
 	struct hotplug_slot hotplug_slot;
 	struct mutex hotplug_lock;
 	struct mutex wmi_lock;
@@ -335,6 +336,15 @@ struct asus_wmi {
 	struct asus_wmi_driver *driver;
 };
 
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+static void asus_wmi_show_deprecated(void)
+{
+	pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi "
+		"is deprecated and will be removed in a future release. Please "
+		"switch over to /sys/class/firmware_attributes.\n");
+}
+#endif
+
 /* WMI ************************************************************************/
 
 static int asus_wmi_evaluate_method3(u32 method_id,
@@ -732,6 +742,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
 }
 
 /* Charging mode, 1=Barrel, 2=USB ******************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t charge_mode_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -742,12 +753,16 @@ static ssize_t charge_mode_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", value & 0xff);
 }
 
 static DEVICE_ATTR_RO(charge_mode);
+#endif
 
 /* dGPU ********************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t dgpu_disable_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -758,6 +773,8 @@ static ssize_t dgpu_disable_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -811,8 +828,10 @@ static ssize_t dgpu_disable_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(dgpu_disable);
+#endif
 
 /* eGPU ********************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t egpu_enable_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -823,6 +842,8 @@ static ssize_t egpu_enable_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -879,8 +900,10 @@ static ssize_t egpu_enable_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(egpu_enable);
+#endif
 
 /* Is eGPU connected? *********************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t egpu_connected_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -891,12 +914,16 @@ static ssize_t egpu_connected_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
 static DEVICE_ATTR_RO(egpu_connected);
+#endif
 
 /* gpu mux switch *************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t gpu_mux_mode_show(struct device *dev,
 				 struct device_attribute *attr, char *buf)
 {
@@ -907,6 +934,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -965,6 +994,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(gpu_mux_mode);
+#endif
 
 /* TUF Laptop Keyboard RGB Modes **********************************************/
 static ssize_t kbd_rgb_mode_store(struct device *dev,
@@ -1088,6 +1118,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
 };
 
 /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t ppt_pl2_sppt_store(struct device *dev,
 				    struct device_attribute *attr,
 				    const char *buf, size_t count)
@@ -1126,6 +1157,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt);
 }
 static DEVICE_ATTR_RW(ppt_pl2_sppt);
@@ -1168,6 +1201,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl);
 }
 static DEVICE_ATTR_RW(ppt_pl1_spl);
@@ -1211,6 +1246,8 @@ static ssize_t ppt_fppt_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->ppt_fppt);
 }
 static DEVICE_ATTR_RW(ppt_fppt);
@@ -1254,6 +1291,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt);
 }
 static DEVICE_ATTR_RW(ppt_apu_sppt);
@@ -1297,6 +1336,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt);
 }
 static DEVICE_ATTR_RW(ppt_platform_sppt);
@@ -1340,6 +1381,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost);
 }
 static DEVICE_ATTR_RW(nv_dynamic_boost);
@@ -1383,11 +1426,15 @@ static ssize_t nv_temp_target_show(struct device *dev,
 {
 	struct asus_wmi *asus = dev_get_drvdata(dev);
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%u\n", asus->nv_temp_target);
 }
 static DEVICE_ATTR_RW(nv_temp_target);
+#endif
 
 /* Ally MCU Powersave ********************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t mcu_powersave_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -1398,6 +1445,8 @@ static ssize_t mcu_powersave_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -1433,6 +1482,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(mcu_powersave);
+#endif
 
 /* Battery ********************************************************************/
 
@@ -2306,6 +2356,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
 }
 
 /* Panel Overdrive ************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t panel_od_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -2316,6 +2367,8 @@ static ssize_t panel_od_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -2352,9 +2405,10 @@ static ssize_t panel_od_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(panel_od);
+#endif
 
 /* Bootup sound ***************************************************************/
-
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t boot_sound_show(struct device *dev,
 			     struct device_attribute *attr, char *buf)
 {
@@ -2365,6 +2419,8 @@ static ssize_t boot_sound_show(struct device *dev,
 	if (result < 0)
 		return result;
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", result);
 }
 
@@ -2400,8 +2456,10 @@ static ssize_t boot_sound_store(struct device *dev,
 	return count;
 }
 static DEVICE_ATTR_RW(boot_sound);
+#endif
 
 /* Mini-LED mode **************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t mini_led_mode_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -2432,6 +2490,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
 		}
 	}
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "%d\n", value);
 }
 
@@ -2502,10 +2562,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev,
 		return sysfs_emit(buf, "0 1 2\n");
 	}
 
+	asus_wmi_show_deprecated();
+
 	return sysfs_emit(buf, "0\n");
 }
 
 static DEVICE_ATTR_RO(available_mini_led_mode);
+#endif
 
 /* Quirks *********************************************************************/
 
@@ -3804,6 +3867,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 static ssize_t throttle_thermal_policy_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
@@ -3847,6 +3911,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
  * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
  */
 static DEVICE_ATTR_RW(throttle_thermal_policy);
+#endif
 
 /* Platform profile ***********************************************************/
 static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
@@ -4474,27 +4539,29 @@ static struct attribute *platform_attributes[] = {
 	&dev_attr_camera.attr,
 	&dev_attr_cardr.attr,
 	&dev_attr_touchpad.attr,
-	&dev_attr_charge_mode.attr,
-	&dev_attr_egpu_enable.attr,
-	&dev_attr_egpu_connected.attr,
-	&dev_attr_dgpu_disable.attr,
-	&dev_attr_gpu_mux_mode.attr,
 	&dev_attr_lid_resume.attr,
 	&dev_attr_als_enable.attr,
 	&dev_attr_fan_boost_mode.attr,
-	&dev_attr_throttle_thermal_policy.attr,
-	&dev_attr_ppt_pl2_sppt.attr,
-	&dev_attr_ppt_pl1_spl.attr,
-	&dev_attr_ppt_fppt.attr,
-	&dev_attr_ppt_apu_sppt.attr,
-	&dev_attr_ppt_platform_sppt.attr,
-	&dev_attr_nv_dynamic_boost.attr,
-	&dev_attr_nv_temp_target.attr,
-	&dev_attr_mcu_powersave.attr,
-	&dev_attr_boot_sound.attr,
-	&dev_attr_panel_od.attr,
-	&dev_attr_mini_led_mode.attr,
-	&dev_attr_available_mini_led_mode.attr,
+	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+		&dev_attr_charge_mode.attr,
+		&dev_attr_egpu_enable.attr,
+		&dev_attr_egpu_connected.attr,
+		&dev_attr_dgpu_disable.attr,
+		&dev_attr_gpu_mux_mode.attr,
+		&dev_attr_ppt_pl2_sppt.attr,
+		&dev_attr_ppt_pl1_spl.attr,
+		&dev_attr_ppt_fppt.attr,
+		&dev_attr_ppt_apu_sppt.attr,
+		&dev_attr_ppt_platform_sppt.attr,
+		&dev_attr_nv_dynamic_boost.attr,
+		&dev_attr_nv_temp_target.attr,
+		&dev_attr_mcu_powersave.attr,
+		&dev_attr_boot_sound.attr,
+		&dev_attr_panel_od.attr,
+		&dev_attr_mini_led_mode.attr,
+		&dev_attr_available_mini_led_mode.attr,
+		&dev_attr_throttle_thermal_policy.attr,
+	#endif
 	NULL
 };
 
@@ -4516,7 +4583,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
 		devid = ASUS_WMI_DEVID_LID_RESUME;
 	else if (attr == &dev_attr_als_enable.attr)
 		devid = ASUS_WMI_DEVID_ALS_ENABLE;
-	else if (attr == &dev_attr_charge_mode.attr)
+	else if (attr == &dev_attr_fan_boost_mode.attr)
+		ok = asus->fan_boost_mode_available;
+
+	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
+	if (attr == &dev_attr_charge_mode.attr)
 		devid = ASUS_WMI_DEVID_CHARGE_MODE;
 	else if (attr == &dev_attr_egpu_enable.attr)
 		ok = asus->egpu_enable_available;
@@ -4554,6 +4625,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
 		ok = asus->mini_led_dev_id != 0;
 	else if (attr == &dev_attr_available_mini_led_mode.attr)
 		ok = asus->mini_led_dev_id != 0;
+	#endif
 
 	if (devid != -1) {
 		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -4794,6 +4866,7 @@ static int asus_wmi_add(struct platform_device *pdev)
 		goto fail_platform;
 
 	/* ensure defaults for tunables */
+	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
 	asus->ppt_pl2_sppt = 5;
 	asus->ppt_pl1_spl = 5;
 	asus->ppt_apu_sppt = 5;
@@ -4818,16 +4891,17 @@ static int asus_wmi_add(struct platform_device *pdev)
 	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO))
 		asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO;
 
-	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
-		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
-	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
-		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
-
+	#endif /* CONFIG_ASUS_WMI_DEPRECATED_ATTRS */
 	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
 		asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
 	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
 		asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
 
+	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
+		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
+	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
+		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
+
 	err = fan_boost_mode_check_present(asus);
 	if (err)
 		goto fail_fan_boost_mode;
-- 
2.46.1


^ permalink raw reply related	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI)
  2024-09-26  9:29 ` [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI) Luke D. Jones
@ 2024-09-26 11:54   ` Jiri Kosina
  0 siblings, 0 replies; 39+ messages in thread
From: Jiri Kosina @ 2024-09-26 11:54 UTC (permalink / raw)
  To: Luke D. Jones
  Cc: linux-kernel, linux-input, bentiss, platform-driver-x86,
	ilpo.jarvinen, hdegoede, corentin.chary, superm1

On Thu, 26 Sep 2024, Luke D. Jones wrote:

> A small change to asus_wmi_evaluate_method() was introduced during
> asus-armoury driver development to put the exports behind a namespace.
> 
> Import that namespace here.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>

Feel free to add

	Acked-by: Jiri Kosina <jkosina@suse.com>

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 0/9] platform/x86: introduce asus-armoury driver
  2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
                   ` (8 preceding siblings ...)
  2024-09-26  9:29 ` [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
@ 2024-09-26 14:50 ` Mario Limonciello
  2024-09-26 21:44   ` Luke Jones
  9 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 14:50 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> his is the first major patch I've ever done with the intention of

s/his/This/

> introducing a new module, so it's highly likely I've made some mistakes
> or misunderstood something.
> 
> TL;DR:
> 1. introduce new module to contain bios attributes, using fw_attributes_class
> 2. deprecate all possible attributes from asus-wmi that were added ad-hoc
> 3. remove those in the next LTS cycle
> 
> The idea for this originates from a conversation with Mario Limonciello
> https://lore.kernel.org/platform-driver-x86/371d4109-a3bb-4c3b-802f-4ec27a945c99@amd.com/
> 
> It is without a doubt much cleaner to use, easier to discover, and the
> API is well defined as opposed to the random clutter of attributes I had
> been placing in the platform sysfs.
> 
> There is some discussion on-going regarding the way tuning knobs such as
> the PPT_* should work with platform_profile. This may result in the creation
> of an extra profile type "Custom" to signify that the user has adjusted
> things away from the defaults used by profiles such as "balanced" or "quiet".

Yeah this is under discussion on my RFC patch series.  Based on the 
outcome of that we can modify asus-armoury later on for it.

> 
> Regards,
> Luke
> 
> Changelog:
> - v1
>    - Initial submission
> - v2
>    - Too many changes to list, but all concerns raised in previous submission addressed.
>    - History: https://lore.kernel.org/platform-driver-x86/20240716051612.64842-1-luke@ljones.dev/
> - v3
>    - All concerns addressed.
>    - History: https://lore.kernel.org/platform-driver-x86/20240806020747.365042-1-luke@ljones.dev/
> - v4
>    - Use EXPORT_SYMBOL_NS_GPL() for the symbols required in this patch series
>    - Add patch for hid-asus due to the use of EXPORT_SYMBOL_NS_GPL()
>    - Split the PPT knobs out to a separate patch
>    - Split the hd_panel setting out to a new patch
>    - Clarify some of APU MEM configuration and convert int to hex
>    - Rename deprecated Kconfig option to ASUS_WMI_DEPRECATED_ATTRS
>    - Fixup cyclic dependency in Kconfig
> 
> Luke D. Jones (9):
>    platform/x86: asus-wmi: export symbols used for read/write WMI
>    hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI)
>    platform/x86: asus-armoury: move existing tunings to asus-armoury
>      module
>    platform/x86: asus-armoury: add panel_hd_mode attribute
>    platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
>    platform/x86: asus-armoury: add dgpu tgp control
>    platform/x86: asus-armoury: add apu-mem control support
>    platform/x86: asus-armoury: add core count control
>    platform/x86: asus-wmi: deprecate bios features
> 
>   .../ABI/testing/sysfs-platform-asus-wmi       |   17 +
>   drivers/hid/hid-asus.c                        |    1 +
>   drivers/platform/x86/Kconfig                  |   22 +
>   drivers/platform/x86/Makefile                 |    1 +
>   drivers/platform/x86/asus-armoury.c           | 1051 +++++++++++++++++
>   drivers/platform/x86/asus-armoury.h           |  257 ++++
>   drivers/platform/x86/asus-wmi.c               |  185 ++-
>   include/linux/platform_data/x86/asus-wmi.h    |   19 +
>   8 files changed, 1520 insertions(+), 33 deletions(-)
>   create mode 100644 drivers/platform/x86/asus-armoury.c
>   create mode 100644 drivers/platform/x86/asus-armoury.h
> 


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
  2024-09-26  9:29 ` [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
@ 2024-09-26 14:56   ` Mario Limonciello
  2024-09-26 22:04     ` Luke Jones
  2024-09-28  0:13   ` kernel test robot
  1 sibling, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 14:56 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> With the existence of the asus-bioscfg module the attributes no-longer
> need to live under the /sys/devices/platform/asus-nb-wmi/ path.
> 
> Deprecate all those that were implemented in asus-bioscfg with the goal
> of removing them fully in the next LTS cycle.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>

I have some very minor nits below.  With them fixed:

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

> ---
>   .../ABI/testing/sysfs-platform-asus-wmi       |  17 +++
>   drivers/platform/x86/Kconfig                  |   9 ++
>   drivers/platform/x86/asus-wmi.c               | 134 ++++++++++++++----
>   3 files changed, 130 insertions(+), 30 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 28144371a0f1..765d50b0d9df 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -63,6 +63,7 @@ Date:		Aug 2022
>   KernelVersion:	6.1
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Switch the GPU hardware MUX mode. Laptops with this feature can
>   		can be toggled to boot with only the dGPU (discrete mode) or in
>   		standard Optimus/Hybrid mode. On switch a reboot is required:
> @@ -75,6 +76,7 @@ Date:		Aug 2022
>   KernelVersion:	5.17
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Disable discrete GPU:
>   			* 0 - Enable dGPU,
>   			* 1 - Disable dGPU
> @@ -84,6 +86,7 @@ Date:		Aug 2022
>   KernelVersion:	5.17
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Enable the external GPU paired with ROG X-Flow laptops.
>   		Toggling this setting will also trigger ACPI to disable the dGPU:
>   
> @@ -95,6 +98,7 @@ Date:		Aug 2022
>   KernelVersion:	5.17
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Enable an LCD response-time boost to reduce or remove ghosting:
>   			* 0 - Disable,
>   			* 1 - Enable
> @@ -104,6 +108,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Get the current charging mode being used:
>   			* 1 - Barrel connected charger,
>   			* 2 - USB-C charging
> @@ -114,6 +119,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Show if the egpu (XG Mobile) is correctly connected:
>   			* 0 - False,
>   			* 1 - True
> @@ -123,6 +129,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Change the mini-LED mode:
>   			* 0 - Single-zone,
>   			* 1 - Multi-zone
> @@ -133,6 +140,7 @@ Date:		Apr 2024
>   KernelVersion:	6.10
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		List the available mini-led modes.
>   
>   What:		/sys/devices/platform/<platform>/ppt_pl1_spl
> @@ -140,6 +148,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
>   		Shown on Intel+Nvidia or AMD+Nvidia based systems:
>   
> @@ -150,6 +159,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
>   		on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
>   
> @@ -160,6 +170,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
>   			* min=5, max=250
>   
> @@ -168,6 +179,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the APU SPPT limit. Shown on full AMD systems only:
>   			* min=5, max=130
>   
> @@ -176,6 +188,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the platform SPPT limit. Shown on full AMD systems only:
>   			* min=5, max=130
>   
> @@ -184,6 +197,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the dynamic boost limit of the Nvidia dGPU:
>   			* min=5, max=25
>   
> @@ -192,6 +206,7 @@ Date:		Jun 2023
>   KernelVersion:	6.5
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set the target temperature limit of the Nvidia dGPU:
>   			* min=75, max=87
>   
> @@ -200,6 +215,7 @@ Date:		Apr 2024
>   KernelVersion:	6.10
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set if the BIOS POST sound is played on boot.
>   			* 0 - False,
>   			* 1 - True
> @@ -209,6 +225,7 @@ Date:		Apr 2024
>   KernelVersion:	6.10
>   Contact:	"Luke Jones" <luke@ljones.dev>
>   Description:
> +        DEPRECATED, WILL BE REMOVED SOON
>   		Set if the MCU can go in to low-power mode on system sleep
>   			* 0 - False,
>   			* 1 - True
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index dedf66e0d099..baa36413f6ed 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -300,6 +300,15 @@ config ASUS_WMI
>   	  To compile this driver as a module, choose M here: the module will
>   	  be called asus-wmi.
>   
> +config ASUS_WMI_DEPRECATED_ATTRS
> +	bool "BIOS option support in WMI platform (DEPRECATED)"
> +	depends on ASUS_WMI
> +	default y
> +	help
> +	  Say Y to expose the configurable BIOS options through the asus-wmi
> +	  driver. This can be used with or without the new asus-armoury driver which

Don't use the word "new" in a description.

> +	  hasthe same attributes, but more, and better features.

has the

> +
>   config ASUS_NB_WMI
>   	tristate "Asus Notebook WMI Driver"
>   	depends on ASUS_WMI
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 0a5221d65130..f553c0b33da7 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -289,11 +289,12 @@ struct asus_wmi {
>   	u8 fan_boost_mode_mask;
>   	u8 fan_boost_mode;
>   
> +
> +	/* Tunables provided by ASUS for gaming laptops */
> +	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)

Typically I would avoid indending the #if and #else.

>   	bool egpu_enable_available;
>   	bool dgpu_disable_available;
>   	u32 gpu_mux_dev;
> -
> -	/* Tunables provided by ASUS for gaming laptops */
>   	u32 ppt_pl2_sppt;
>   	u32 ppt_pl1_spl;
>   	u32 ppt_apu_sppt;
> @@ -301,6 +302,9 @@ struct asus_wmi {
>   	u32 ppt_fppt;
>   	u32 nv_dynamic_boost;
>   	u32 nv_temp_target;
> +	bool panel_overdrive_available;
> +	u32 mini_led_dev_id;
> +	#endif

Typically I would avoid indending the #if and #else.

>   
>   	u32 kbd_rgb_dev;
>   	bool kbd_rgb_state_available;
> @@ -319,9 +323,6 @@ struct asus_wmi {
>   	// The RSOC controls the maximum charging percentage.
>   	bool battery_rsoc_available;
>   
> -	bool panel_overdrive_available;
> -	u32 mini_led_dev_id;
> -
>   	struct hotplug_slot hotplug_slot;
>   	struct mutex hotplug_lock;
>   	struct mutex wmi_lock;
> @@ -335,6 +336,15 @@ struct asus_wmi {
>   	struct asus_wmi_driver *driver;
>   };
>   
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> +static void asus_wmi_show_deprecated(void)
> +{
> +	pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi "
> +		"is deprecated and will be removed in a future release. Please "
> +		"switch over to /sys/class/firmware_attributes.\n");
> +}
> +#endif
> +
>   /* WMI ************************************************************************/
>   
>   static int asus_wmi_evaluate_method3(u32 method_id,
> @@ -732,6 +742,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
>   }
>   
>   /* Charging mode, 1=Barrel, 2=USB ******************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t charge_mode_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -742,12 +753,16 @@ static ssize_t charge_mode_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", value & 0xff);
>   }
>   
>   static DEVICE_ATTR_RO(charge_mode);
> +#endif
>   
>   /* dGPU ********************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t dgpu_disable_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -758,6 +773,8 @@ static ssize_t dgpu_disable_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -811,8 +828,10 @@ static ssize_t dgpu_disable_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(dgpu_disable);
> +#endif
>   
>   /* eGPU ********************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t egpu_enable_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -823,6 +842,8 @@ static ssize_t egpu_enable_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -879,8 +900,10 @@ static ssize_t egpu_enable_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(egpu_enable);
> +#endif
>   
>   /* Is eGPU connected? *********************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t egpu_connected_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -891,12 +914,16 @@ static ssize_t egpu_connected_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
>   static DEVICE_ATTR_RO(egpu_connected);
> +#endif
>   
>   /* gpu mux switch *************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t gpu_mux_mode_show(struct device *dev,
>   				 struct device_attribute *attr, char *buf)
>   {
> @@ -907,6 +934,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -965,6 +994,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(gpu_mux_mode);
> +#endif
>   
>   /* TUF Laptop Keyboard RGB Modes **********************************************/
>   static ssize_t kbd_rgb_mode_store(struct device *dev,
> @@ -1088,6 +1118,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
>   };
>   
>   /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t ppt_pl2_sppt_store(struct device *dev,
>   				    struct device_attribute *attr,
>   				    const char *buf, size_t count)
> @@ -1126,6 +1157,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt);
>   }
>   static DEVICE_ATTR_RW(ppt_pl2_sppt);
> @@ -1168,6 +1201,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl);
>   }
>   static DEVICE_ATTR_RW(ppt_pl1_spl);
> @@ -1211,6 +1246,8 @@ static ssize_t ppt_fppt_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->ppt_fppt);
>   }
>   static DEVICE_ATTR_RW(ppt_fppt);
> @@ -1254,6 +1291,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt);
>   }
>   static DEVICE_ATTR_RW(ppt_apu_sppt);
> @@ -1297,6 +1336,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt);
>   }
>   static DEVICE_ATTR_RW(ppt_platform_sppt);
> @@ -1340,6 +1381,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost);
>   }
>   static DEVICE_ATTR_RW(nv_dynamic_boost);
> @@ -1383,11 +1426,15 @@ static ssize_t nv_temp_target_show(struct device *dev,
>   {
>   	struct asus_wmi *asus = dev_get_drvdata(dev);
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%u\n", asus->nv_temp_target);
>   }
>   static DEVICE_ATTR_RW(nv_temp_target);
> +#endif
>   
>   /* Ally MCU Powersave ********************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t mcu_powersave_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -1398,6 +1445,8 @@ static ssize_t mcu_powersave_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -1433,6 +1482,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(mcu_powersave);
> +#endif
>   
>   /* Battery ********************************************************************/
>   
> @@ -2306,6 +2356,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
>   }
>   
>   /* Panel Overdrive ************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t panel_od_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -2316,6 +2367,8 @@ static ssize_t panel_od_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -2352,9 +2405,10 @@ static ssize_t panel_od_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(panel_od);
> +#endif
>   
>   /* Bootup sound ***************************************************************/
> -
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t boot_sound_show(struct device *dev,
>   			     struct device_attribute *attr, char *buf)
>   {
> @@ -2365,6 +2419,8 @@ static ssize_t boot_sound_show(struct device *dev,
>   	if (result < 0)
>   		return result;
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", result);
>   }
>   
> @@ -2400,8 +2456,10 @@ static ssize_t boot_sound_store(struct device *dev,
>   	return count;
>   }
>   static DEVICE_ATTR_RW(boot_sound);
> +#endif
>   
>   /* Mini-LED mode **************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t mini_led_mode_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -2432,6 +2490,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
>   		}
>   	}
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "%d\n", value);
>   }
>   
> @@ -2502,10 +2562,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev,
>   		return sysfs_emit(buf, "0 1 2\n");
>   	}
>   
> +	asus_wmi_show_deprecated();
> +
>   	return sysfs_emit(buf, "0\n");
>   }
>   
>   static DEVICE_ATTR_RO(available_mini_led_mode);
> +#endif
>   
>   /* Quirks *********************************************************************/
>   
> @@ -3804,6 +3867,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
>   	return 0;
>   }
>   
> +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   static ssize_t throttle_thermal_policy_show(struct device *dev,
>   				   struct device_attribute *attr, char *buf)
>   {
> @@ -3847,6 +3911,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
>    * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
>    */
>   static DEVICE_ATTR_RW(throttle_thermal_policy);
> +#endif
>   
>   /* Platform profile ***********************************************************/
>   static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
> @@ -4474,27 +4539,29 @@ static struct attribute *platform_attributes[] = {
>   	&dev_attr_camera.attr,
>   	&dev_attr_cardr.attr,
>   	&dev_attr_touchpad.attr,
> -	&dev_attr_charge_mode.attr,
> -	&dev_attr_egpu_enable.attr,
> -	&dev_attr_egpu_connected.attr,
> -	&dev_attr_dgpu_disable.attr,
> -	&dev_attr_gpu_mux_mode.attr,
>   	&dev_attr_lid_resume.attr,
>   	&dev_attr_als_enable.attr,
>   	&dev_attr_fan_boost_mode.attr,
> -	&dev_attr_throttle_thermal_policy.attr,
> -	&dev_attr_ppt_pl2_sppt.attr,
> -	&dev_attr_ppt_pl1_spl.attr,
> -	&dev_attr_ppt_fppt.attr,
> -	&dev_attr_ppt_apu_sppt.attr,
> -	&dev_attr_ppt_platform_sppt.attr,
> -	&dev_attr_nv_dynamic_boost.attr,
> -	&dev_attr_nv_temp_target.attr,
> -	&dev_attr_mcu_powersave.attr,
> -	&dev_attr_boot_sound.attr,
> -	&dev_attr_panel_od.attr,
> -	&dev_attr_mini_led_mode.attr,
> -	&dev_attr_available_mini_led_mode.attr,
> +	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> +		&dev_attr_charge_mode.attr,
> +		&dev_attr_egpu_enable.attr,
> +		&dev_attr_egpu_connected.attr,
> +		&dev_attr_dgpu_disable.attr,
> +		&dev_attr_gpu_mux_mode.attr,
> +		&dev_attr_ppt_pl2_sppt.attr,
> +		&dev_attr_ppt_pl1_spl.attr,
> +		&dev_attr_ppt_fppt.attr,
> +		&dev_attr_ppt_apu_sppt.attr,
> +		&dev_attr_ppt_platform_sppt.attr,
> +		&dev_attr_nv_dynamic_boost.attr,
> +		&dev_attr_nv_temp_target.attr,
> +		&dev_attr_mcu_powersave.attr,
> +		&dev_attr_boot_sound.attr,
> +		&dev_attr_panel_od.attr,
> +		&dev_attr_mini_led_mode.attr,
> +		&dev_attr_available_mini_led_mode.attr,
> +		&dev_attr_throttle_thermal_policy.attr,
> +	#endif
>   	NULL
>   };
>   
> @@ -4516,7 +4583,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
>   		devid = ASUS_WMI_DEVID_LID_RESUME;
>   	else if (attr == &dev_attr_als_enable.attr)
>   		devid = ASUS_WMI_DEVID_ALS_ENABLE;
> -	else if (attr == &dev_attr_charge_mode.attr)
> +	else if (attr == &dev_attr_fan_boost_mode.attr)
> +		ok = asus->fan_boost_mode_available;
> +
> +	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> +	if (attr == &dev_attr_charge_mode.attr)
>   		devid = ASUS_WMI_DEVID_CHARGE_MODE;
>   	else if (attr == &dev_attr_egpu_enable.attr)
>   		ok = asus->egpu_enable_available;
> @@ -4554,6 +4625,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
>   		ok = asus->mini_led_dev_id != 0;
>   	else if (attr == &dev_attr_available_mini_led_mode.attr)
>   		ok = asus->mini_led_dev_id != 0;
> +	#endif
>   
>   	if (devid != -1) {
>   		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
> @@ -4794,6 +4866,7 @@ static int asus_wmi_add(struct platform_device *pdev)
>   		goto fail_platform;
>   
>   	/* ensure defaults for tunables */
> +	#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
>   	asus->ppt_pl2_sppt = 5;
>   	asus->ppt_pl1_spl = 5;
>   	asus->ppt_apu_sppt = 5;
> @@ -4818,16 +4891,17 @@ static int asus_wmi_add(struct platform_device *pdev)
>   	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO))
>   		asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO;
>   
> -	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
> -		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
> -	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
> -		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
> -
> +	#endif /* CONFIG_ASUS_WMI_DEPRECATED_ATTRS */
>   	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
>   		asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
>   	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
>   		asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
>   
> +	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
> +		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
> +	else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
> +		asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
> +
>   	err = fan_boost_mode_check_present(asus);
>   	if (err)
>   		goto fail_fan_boost_mode;


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute
  2024-09-26  9:29 ` [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute Luke D. Jones
@ 2024-09-26 15:17   ` Mario Limonciello
  2024-09-26 22:12     ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:17 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> Add panel_hd_mode to toggle the panel mode between single and high
> definition modes.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>

This patch looks good to me.

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

---

But that being said; mostly to satisfy my curiosity could you share more 
about what this actually does?

Does it change the EDID exposed in the BIOS in ACPI _DDC?  At least for 
AMD platforms that would mean it only works with this patch (which is on 
it's way):

https://lore.kernel.org/amd-gfx/20240918213845.158293-11-mario.limonciello@amd.com/

> ---
>   drivers/platform/x86/asus-armoury.c        | 6 +++++-
>   include/linux/platform_data/x86/asus-wmi.h | 1 +
>   2 files changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> index 39e422b16b8e..15eab4d45b81 100644
> --- a/drivers/platform/x86/asus-armoury.c
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -106,7 +106,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
>   
>   static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
>   {
> -	return !strcmp(attr->attr.name, "gpu_mux_mode");
> +	return !strcmp(attr->attr.name, "gpu_mux_mode") ||
> +	       !strcmp(attr->attr.name, "panel_hd_mode");
>   }
>   
>   /**
> @@ -429,6 +430,8 @@ ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
>   		   "Set MCU powersaving mode");
>   ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
>   		   "Set the panel refresh overdrive");
> +ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD,
> +		   "Set the panel HD mode to UHD<0> or FHD<1>");
>   ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
>   		   "Show the eGPU connection status");
>   
> @@ -442,6 +445,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>   	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
>   	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
>   	{ &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
> +	{ &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD },
>   };
>   
>   static int asus_fw_attr_add(void)
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 6ea4dedfb85e..7caf2c7ed8c9 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -73,6 +73,7 @@
>   #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
>   
>   /* Misc */
> +#define ASUS_WMI_DEVID_PANEL_HD		0x0005001C
>   #define ASUS_WMI_DEVID_PANEL_OD		0x00050019
>   #define ASUS_WMI_DEVID_CAMERA		0x00060013
>   #define ASUS_WMI_DEVID_LID_FLIP		0x00060062


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
  2024-09-26  9:29 ` [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs Luke D. Jones
@ 2024-09-26 15:22   ` Mario Limonciello
  2024-09-26 22:39     ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:22 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> Adds the ppt_* and nv_* tuning knobs that are available via WMI methods
> and adds proper min/max levels plus defaults.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
>   drivers/platform/x86/asus-armoury.c | 130 ++++++++++++++++++++++++++++
>   drivers/platform/x86/asus-armoury.h |  65 ++++++++++++++
>   2 files changed, 195 insertions(+)
> 
> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> index 15eab4d45b81..766f944d0233 100644
> --- a/drivers/platform/x86/asus-armoury.c
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -52,12 +52,40 @@
>   #define NVIDIA_TEMP_MIN 75
>   #define NVIDIA_TEMP_MAX 87
>   
> +/* Tunables provided by ASUS for gaming laptops */
> +struct rog_tunables {
> +	u32 cpu_default;
> +	u32 cpu_min;
> +	u32 cpu_max;
> +
> +	u32 platform_default;
> +	u32 platform_min;
> +	u32 platform_max;
> +
> +	u32 ppt_pl1_spl; // cpu
> +	u32 ppt_pl2_sppt; // cpu
> +	u32 ppt_apu_sppt; // plat
> +	u32 ppt_platform_sppt; // plat
> +	u32 ppt_fppt; // cpu
> +
> +	u32 nv_boost_default;
> +	u32 nv_boost_min;
> +	u32 nv_boost_max;
> +	u32 nv_dynamic_boost;
> +
> +	u32 nv_temp_default;
> +	u32 nv_temp_min;
> +	u32 nv_temp_max;
> +	u32 nv_temp_target;
> +};
> +
>   static const struct class *fw_attr_class;
>   
>   struct asus_armoury_priv {
>   	struct device *fw_attr_dev;
>   	struct kset *fw_attr_kset;
>   
> +	struct rog_tunables *rog_tunables;
>   	u32 mini_led_dev_id;
>   	u32 gpu_mux_dev_id;
>   
> @@ -421,6 +449,25 @@ WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
>   ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
>   
>   /* Simple attribute creation */
> +ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
> +		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> +ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, cpu_default,
> +		       cpu_min, cpu_max, 1, "Set the CPU fast package limit");
> +ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT,
> +		       platform_default, platform_min, platform_max, 1,
> +		       "Set the CPU slow package limit");
> +ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT,
> +		       platform_default, platform_min, platform_max, 1,
> +		       "Set the CPU slow package limit");
> +ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, cpu_default, cpu_min,
> +		       cpu_max, 1, "Set the CPU slow package limit");
> +ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST,
> +		       nv_boost_default, nv_boost_min, nv_boost_max, 1,
> +		       "Set the Nvidia dynamic boost limit");
> +ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET,
> +		       nv_temp_default, nv_boost_min, nv_temp_max, 1,
> +		       "Set the Nvidia max thermal limit");
> +
>   ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
>   		       "Show the current mode of charging");
>   
> @@ -441,6 +488,14 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>   	{ &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
>   	{ &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
>   
> +	{ &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL },
> +	{ &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT },
> +	{ &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT },
> +	{ &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT },
> +	{ &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT },
> +	{ &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
> +	{ &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
> +
>   	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
>   	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
>   	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
> @@ -532,12 +587,87 @@ static int asus_fw_attr_add(void)
>   
>   /* Init / exit ****************************************************************/
>   
> +/* Set up the min/max and defaults for ROG tunables */
> +static void init_rog_tunables(struct rog_tunables *rog)
> +{
> +	const char *product;
> +	u32 max_boost = NVIDIA_BOOST_MAX;
> +	u32 cpu_default = PPT_CPU_LIMIT_DEFAULT;
> +	u32 cpu_max = PPT_CPU_LIMIT_MAX;
> +	u32 platform_default = PPT_PLATFORM_DEFAULT;
> +	u32 platform_max = PPT_PLATFORM_MAX;

Reverse xmas tree here.

> +
> +	/*
> +	 * ASUS product_name contains everything required, e.g,
> +	 * "ROG Flow X16 GV601VV_GV601VV_00185149B"
> +	 */
> +	product = dmi_get_system_info(DMI_PRODUCT_NAME);

It's really too bad there isn't somewhere to programatically get the 
correct upper bounds in their API.

I'm wondering if you want something "like" this:

if (!product)
	pr_notice("Unknown hardware found.  Setting safe limits, please report 
to get limits corrected\n");

> +
> +	if (strstr(product, "GA402R")) {
> +		cpu_default = 125;
> +	} else if (strstr(product, "13QY")) {
> +		cpu_max = 250;
> +	} else if (strstr(product, "X13")) {
> +		cpu_max = 75;
> +		cpu_default = 50;
> +	} else if (strstr(product, "RC71") || strstr(product, "RC72")) {
> +		cpu_max = 50;
> +		cpu_default = 30;
> +	} else if (strstr(product, "G814") || strstr(product, "G614") ||
> +		   strstr(product, "G834") || strstr(product, "G634")) {
> +		cpu_max = 175;
> +	} else if (strstr(product, "GA402X") || strstr(product, "GA403") ||
> +		   strstr(product, "FA507N") || strstr(product, "FA507X") ||
> +		   strstr(product, "FA707N") || strstr(product, "FA707X")) {
> +		cpu_max = 90;
> +	}
> +
> +	if (strstr(product, "GZ301ZE"))
> +		max_boost = 5;
> +	else if (strstr(product, "FX507ZC4"))
> +		max_boost = 15;
> +	else if (strstr(product, "GU605"))
> +		max_boost = 20;
> +
> +	/* ensure defaults for tunables */
> +	rog->cpu_default = cpu_default;
> +	rog->cpu_min = PPT_CPU_LIMIT_MIN;
> +	rog->cpu_max = cpu_max;
> +
> +	rog->platform_default = platform_default;
> +	rog->platform_max = PPT_PLATFORM_MIN;
> +	rog->platform_max = platform_max;
> +
> +	rog->ppt_pl1_spl = cpu_default;
> +	rog->ppt_pl2_sppt = cpu_default;
> +	rog->ppt_apu_sppt = cpu_default;
> +
> +	rog->ppt_platform_sppt = platform_default;
> +	rog->ppt_fppt = cpu_default;
> +
> +	rog->nv_boost_default = NVIDIA_BOOST_MAX;
> +	rog->nv_boost_max = NVIDIA_BOOST_MIN;
> +	rog->nv_boost_max = max_boost;
> +	rog->nv_dynamic_boost = NVIDIA_BOOST_MIN;
> +
> +	rog->nv_temp_default = NVIDIA_TEMP_MAX;
> +	rog->nv_temp_max = NVIDIA_TEMP_MIN;
> +	rog->nv_temp_max = NVIDIA_TEMP_MAX;
> +	rog->nv_temp_target = NVIDIA_TEMP_MIN;
> +}
> +
>   static int __init asus_fw_init(void)
>   {
>   	int err;
>   
>   	fw_attrs.pending_reboot = false;
>   
> +	asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL);
> +	if (!asus_armoury.rog_tunables)
> +		return -ENOMEM;
> +
> +	init_rog_tunables(asus_armoury.rog_tunables);
> +
>   	err = asus_fw_attr_add();
>   	if (err)
>   		return err;
> diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> index b99fd136abf1..9e63ea0d9d44 100644
> --- a/drivers/platform/x86/asus-armoury.h
> +++ b/drivers/platform/x86/asus-armoury.h
> @@ -17,6 +17,12 @@ static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
>   			      const char *buf, size_t count, u32 min, u32 max,
>   			      u32 *store_value, u32 wmi_dev);
>   
> +static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			     char *buf)
> +{
> +	return sysfs_emit(buf, "integer\n");
> +}
> +
>   static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
>   			      char *buf)
>   {
> @@ -143,4 +149,63 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
>   		.name = _fsname, .attrs = _attrname##_attrs               \
>   	}
>   
> +/*
> + * ROG PPT attributes need a little different in setup as they
> + * require rog_tunables members.
> + */
> +
> +#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi)                             \
> +	static ssize_t _attr##_current_value_store(                           \
> +		struct kobject *kobj, struct kobj_attribute *attr,            \
> +		const char *buf, size_t count)                                \
> +	{                                                                     \
> +		return attr_int_store(kobj, attr, buf, count,                 \
> +				      asus_armoury.rog_tunables->_min,        \
> +				      asus_armoury.rog_tunables->_max,        \
> +				      &asus_armoury.rog_tunables->_attr,      \
> +				      _wmi);                                  \
> +	}                                                                     \
> +	static ssize_t _attr##_current_value_show(                            \
> +		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> +	{                                                                     \
> +		return sysfs_emit(buf, "%u\n",                                \
> +				  asus_armoury.rog_tunables->_attr);          \
> +	}                                                                     \
> +	static struct kobj_attribute attr_##_attr##_current_value =           \
> +		__ASUS_ATTR_RW(_attr, current_value)
> +
> +#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val)                            \
> +	static ssize_t _attrname##_##_prop##_show(                            \
> +		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> +	{                                                                     \
> +		return sysfs_emit(buf, "%d\n",                                \
> +				  asus_armoury.rog_tunables->_val);           \
> +	}                                                                     \
> +	static struct kobj_attribute attr_##_attrname##_##_prop =             \
> +		__ASUS_ATTR_RO(_attrname, _prop)
> +
> +#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, _min, _max, \
> +			       _incstep, _dispname)                            \
> +	__ROG_TUNABLE_SHOW(default_value, _attrname, _default);                \
> +	__ROG_TUNABLE_RW(_attrname, _min, _max, _wmi);                         \
> +	__ROG_TUNABLE_SHOW(min_value, _attrname, _min);                        \
> +	__ROG_TUNABLE_SHOW(max_value, _attrname, _max);                        \
> +	__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep);        \
> +	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);           \
> +	static struct kobj_attribute attr_##_attrname##_type =                 \
> +		__ASUS_ATTR_RO_AS(type, int_type_show);                        \
> +	static struct attribute *_attrname##_attrs[] = {                       \
> +		&attr_##_attrname##_current_value.attr,                        \
> +		&attr_##_attrname##_default_value.attr,                        \
> +		&attr_##_attrname##_min_value.attr,                            \
> +		&attr_##_attrname##_max_value.attr,                            \
> +		&attr_##_attrname##_scalar_increment.attr,                     \
> +		&attr_##_attrname##_display_name.attr,                         \
> +		&attr_##_attrname##_type.attr,                                 \
> +		NULL                                                           \
> +	};                                                                     \
> +	static const struct attribute_group _attrname##_attr_group = {         \
> +		.name = _fsname, .attrs = _attrname##_attrs                    \
> +	}
> +
>   #endif /* _ASUS_BIOSCFG_H_ */


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support
  2024-09-26  9:29 ` [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
@ 2024-09-26 15:25   ` Mario Limonciello
  2024-09-26 22:14     ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:25 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> Implement the APU memory size control under the asus-armoury module using
> the fw_attributes class.
> 
> This allows the APU allocated memory size to be adjusted depending on
> the users priority. A reboot is required after change.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

> ---
>   drivers/platform/x86/asus-armoury.c        | 114 +++++++++++++++++++++
>   include/linux/platform_data/x86/asus-wmi.h |   1 +
>   2 files changed, 115 insertions(+)
> 
> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> index 0f67b5deb629..a0022dcee3a4 100644
> --- a/drivers/platform/x86/asus-armoury.c
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -456,6 +456,119 @@ static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj
>   WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
>   ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
>   
> +/* Device memory available to APU */
> +
> +static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> +					  char *buf)
> +{
> +	int err;
> +	u32 mem;
> +
> +	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem);
> +	if (err)
> +		return err;
> +
> +	switch (mem) {
> +	case 0x100:
> +		mem = 0;
> +		break;
> +	case 0x102:
> +		mem = 1;
> +		break;
> +	case 0x103:
> +		mem = 2;
> +		break;
> +	case 0x104:
> +		mem = 3;
> +		break;
> +	case 0x105:
> +		mem = 4;
> +		break;
> +	case 0x106:
> +		/* This is out of order and looks wrong but is correct */
> +		mem = 8;
> +		break;
> +	case 0x107:
> +		mem = 5;
> +		break;
> +	case 0x108:
> +		mem = 6;
> +		break;
> +	case 0x109:
> +		mem = 7;
> +		break;
> +	default:
> +		mem = 4;
> +		break;
> +	}
> +
> +	return sysfs_emit(buf, "%u\n", mem);
> +}
> +
> +static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> +					   const char *buf, size_t count)
> +{
> +	int result, err;
> +	u32 requested, mem;
> +
> +	result = kstrtou32(buf, 10, &requested);
> +	if (result)
> +		return result;
> +
> +	switch (requested) {
> +	case 0:
> +		mem = 0x000;
> +		break;
> +	case 1:
> +		mem = 0x102;
> +		break;
> +	case 2:
> +		mem = 0x103;
> +		break;
> +	case 3:
> +		mem = 0x104;
> +		break;
> +	case 4:
> +		mem = 0x105;
> +		break;
> +	case 5:
> +		mem = 0x107;
> +		break;
> +	case 6:
> +		mem = 0x108;
> +		break;
> +	case 7:
> +		mem = 0x109;
> +		break;
> +	case 8:
> +		/* This is out of order and looks wrong but is correct */
> +		mem = 0x106;
> +		break;
> +	default:
> +		return -EIO;
> +	}
> +
> +	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result);
> +	if (err) {
> +		pr_warn("Failed to set apu_mem: %d\n", err);
> +		return err;
> +	}
> +
> +	pr_info("APU memory changed to %uGB, reboot required\n", requested);
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +
> +	asus_set_reboot_and_signal_event();
> +
> +	return count;
> +}
> +
> +static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr,
> +					    char *buf)
> +{
> +	return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n");
> +}
> +ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
> +
>   /* Simple attribute creation */
>   ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
>   		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> @@ -511,6 +624,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>   	{ &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
>   	{ &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
>   	{ &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
> +	{ &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
>   
>   	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
>   	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 86629e621c61..e1aeafdf05d5 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -136,6 +136,7 @@
>   
>   #define ASUS_WMI_DEVID_DGPU_BASE_TGP	0x00120099
>   #define ASUS_WMI_DEVID_DGPU_SET_TGP	0x00120098
> +#define ASUS_WMI_DEVID_APU_MEM		0x000600C1
>   
>   /* gpu mux switch, 0 = dGPU, 1 = Optimus */
>   #define ASUS_WMI_DEVID_GPU_MUX		0x00090016


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI
  2024-09-26  9:29 ` [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI Luke D. Jones
@ 2024-09-26 15:26   ` Mario Limonciello
  0 siblings, 0 replies; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:26 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> Export some rather helpful read/write WMI symbols using a namespace.
> These are DEVS and DSTS only, or require the arg0 input.
> 
> Also does a slight refactor of internals of these functions.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>

Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

> ---
>   drivers/platform/x86/asus-wmi.c            | 51 ++++++++++++++++++++--
>   include/linux/platform_data/x86/asus-wmi.h | 10 +++++
>   2 files changed, 58 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 6725a27df62f..0a5221d65130 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -385,7 +385,7 @@ int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
>   {
>   	return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
>   }
> -EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
> +EXPORT_SYMBOL_NS_GPL(asus_wmi_evaluate_method, ASUS_WMI);
>   
>   static int asus_wmi_evaluate_method5(u32 method_id,
>   		u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4, u32 *retval)
> @@ -549,12 +549,57 @@ static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
>   	return 0;
>   }
>   
> -static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
> -				 u32 *retval)
> +/**
> + * asus_wmi_get_devstate_dsts() - Get the WMI function state.
> + * @dev_id: The WMI function to call.
> + * @retval: A pointer to where to store the value returned from WMI.
> + *
> + * The returned WMI function state can also be used to determine if the WMI
> + * function is supported by checking if the asus_wmi_get_devstate_dsts()
> + * returns an error.
> + *
> + * On success the return value is 0, and the retval is a valid value returned
> + * by the successful WMI function call. An error value is returned only if the
> + * WMI function failed, or if it returns "unsupported" which is typically a 0
> + * (no return, and no 'supported' bit set), or a 0xFFFFFFFE (~1) which if not
> + * caught here can result in unexpected behaviour later.
> + */
> +int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
> +{
> +	int err;
> +
> +	err = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, retval);
> +	if (err)
> +		return err;
> +
> +	*retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
> +	if (*retval == ASUS_WMI_UNSUPPORTED_METHOD)
> +		return -ENODEV;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_NS_GPL(asus_wmi_get_devstate_dsts, ASUS_WMI);
> +
> +/**
> + * asus_wmi_set_devstate() - Set the WMI function state.
> + * @dev_id: The WMI function to call.
> + * @ctrl_param: The argument to be used for this WMI function.
> + * @retval: A pointer to where to store the value returned from WMI.
> + *
> + * The returned WMI function state if not checked here for error as
> + * asus_wmi_set_devstate() is not called unless first paired with a call to
> + * asus_wmi_get_devstate_dsts() to check that the WMI function is supported.
> + *
> + * On success the return value is 0, and the retval is a valid value returned
> + * by the successful WMI function call. An error value is returned only if the
> + * WMI function failed.
> + */
> +int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
>   {
>   	return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
>   					ctrl_param, retval);
>   }
> +EXPORT_SYMBOL_NS_GPL(asus_wmi_set_devstate, ASUS_WMI);
>   
>   /* Helper for special devices with magic return codes */
>   static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 365e119bebaa..6ea4dedfb85e 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -158,8 +158,18 @@
>   #define ASUS_WMI_DSTS_LIGHTBAR_MASK	0x0000000F
>   
>   #if IS_REACHABLE(CONFIG_ASUS_WMI)
> +int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval);
> +int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval);
>   int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval);
>   #else
> +static inline int asus_wmi_get_devstate_dsts(u32 dev_id, u32 *retval)
> +{
> +	return -ENODEV;
> +}
> +static inline int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, u32 *retval)
> +{
> +	return -ENODEV;
> +}
>   static inline int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
>   					   u32 *retval)
>   {


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 8/9] platform/x86: asus-armoury: add core count control
  2024-09-26  9:29 ` [PATCH v4 8/9] platform/x86: asus-armoury: add core count control Luke D. Jones
@ 2024-09-26 15:30   ` Mario Limonciello
  2024-09-26 21:47     ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:30 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> Implement Intel core enablement under the asus-armoury module using the
> fw_attributes class.
> 
> This allows users to enable or disable preformance or efficiency cores
> depending on their requirements. After change a reboot is required.
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
>   drivers/platform/x86/asus-armoury.c        | 219 +++++++++++++++++++++
>   drivers/platform/x86/asus-armoury.h        |  28 +++
>   include/linux/platform_data/x86/asus-wmi.h |   4 +
>   3 files changed, 251 insertions(+)
> 
> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> index a0022dcee3a4..ce1facb40bd5 100644
> --- a/drivers/platform/x86/asus-armoury.c
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -40,6 +40,21 @@
>   #define ASUS_MINI_LED_2024_STRONG 0x01
>   #define ASUS_MINI_LED_2024_OFF 0x02
>   
> +#define ASUS_POWER_CORE_MASK GENMASK(15, 8)
> +#define ASUS_PERF_CORE_MASK GENMASK(7, 0)
> +
> +enum cpu_core_type {
> +	CPU_CORE_PERF = 0,
> +	CPU_CORE_POWER,
> +};
> +
> +enum cpu_core_value {
> +	CPU_CORE_DEFAULT = 0,
> +	CPU_CORE_MIN,
> +	CPU_CORE_MAX,
> +	CPU_CORE_CURRENT,
> +};
> +
>   /* Default limits for tunables available on ASUS ROG laptops */
>   #define PPT_CPU_LIMIT_MIN 5
>   #define PPT_CPU_LIMIT_MAX 150
> @@ -85,6 +100,13 @@ struct rog_tunables {
>   	u32 dgpu_tgp_min;
>   	u32 dgpu_tgp_max;
>   	u32 dgpu_tgp;
> +
> +	u32 cur_perf_cores;
> +	u32 min_perf_cores;
> +	u32 max_perf_cores;
> +	u32 cur_power_cores;
> +	u32 min_power_cores;
> +	u32 max_power_cores;
>   };
>   
>   static const struct class *fw_attr_class;
> @@ -143,6 +165,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
>   static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
>   {
>   	return !strcmp(attr->attr.name, "gpu_mux_mode") ||
> +	       !strcmp(attr->attr.name, "cores_performance") ||
> +	       !strcmp(attr->attr.name, "cores_efficiency") ||
>   	       !strcmp(attr->attr.name, "panel_hd_mode");
>   }
>   
> @@ -569,6 +593,198 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at
>   }
>   ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
>   
> +static int init_max_cpu_cores(void)
> +{
> +	u32 cores;
> +	int err;
> +
> +	asus_armoury.rog_tunables->min_perf_cores = 4;
> +	asus_armoury.rog_tunables->max_perf_cores = 4;
> +	asus_armoury.rog_tunables->cur_perf_cores = 4;
> +	asus_armoury.rog_tunables->min_power_cores = 0;
> +	asus_armoury.rog_tunables->max_power_cores = 8;
> +	asus_armoury.rog_tunables->cur_power_cores = 8;

This seems like it's going to be dependent upon "specific" CPU SKU, no?

If you can't detect the bounds from the WMI API I think it would be 
smarter to use the CPU vendor specific CPUID/MSR APIs to discover the 
topology and how many cores of the different types exist.

Furthermore what about LP cores?  I guess those can't be turned and off 
from this API?

> +
> +	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
> +	if (err)
> +		return err;
> +
> +	cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
> +	asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
> +	asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
> +
> +	cores = 0;
> +	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
> +	if (err)
> +		return err;
> +
> +	asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
> +	asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
> +
> +	return 0;
> +}
> +
> +static ssize_t cores_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf,
> +				enum cpu_core_type core_type, enum cpu_core_value core_value)
> +{
> +	u32 cores;
> +
> +	switch (core_value) {
> +	case CPU_CORE_DEFAULT:
> +	case CPU_CORE_MAX:
> +		if (core_type == CPU_CORE_PERF)
> +			return sysfs_emit(buf, "%d\n",
> +					  asus_armoury.rog_tunables->max_perf_cores);
> +		else
> +			return sysfs_emit(buf, "%d\n",
> +					  asus_armoury.rog_tunables->max_power_cores);
> +	case CPU_CORE_MIN:
> +		if (core_type == CPU_CORE_PERF)
> +			return sysfs_emit(buf, "%d\n",
> +					  asus_armoury.rog_tunables->min_perf_cores);
> +		else
> +			return sysfs_emit(buf, "%d\n",
> +					  asus_armoury.rog_tunables->min_power_cores);
> +	default:
> +		break;
> +	}
> +
> +	if (core_type == CPU_CORE_PERF)
> +		cores = asus_armoury.rog_tunables->cur_perf_cores;
> +	else
> +		cores = asus_armoury.rog_tunables->cur_power_cores;
> +
> +	return sysfs_emit(buf, "%d\n", cores);
> +}
> +
> +static ssize_t cores_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> +					 const char *buf, enum cpu_core_type core_type)
> +{
> +	int result, err;
> +	u32 new_cores, perf_cores, powr_cores, out_val, min, max;
> +
> +	result = kstrtou32(buf, 10, &new_cores);
> +	if (result)
> +		return result;
> +
> +	if (core_type == CPU_CORE_PERF) {
> +		perf_cores = new_cores;
> +		powr_cores = out_val = asus_armoury.rog_tunables->cur_power_cores;
> +		min = asus_armoury.rog_tunables->min_perf_cores;
> +		max = asus_armoury.rog_tunables->max_perf_cores;
> +	} else {
> +		perf_cores = asus_armoury.rog_tunables->cur_perf_cores;
> +		powr_cores = out_val = new_cores;
> +		min = asus_armoury.rog_tunables->min_power_cores;
> +		max = asus_armoury.rog_tunables->max_power_cores;
> +	}
> +
> +	if (new_cores < min || new_cores > max)
> +		return -EINVAL;
> +
> +	out_val = 0;
> +	out_val |= FIELD_PREP(ASUS_PERF_CORE_MASK, perf_cores);
> +	out_val |= FIELD_PREP(ASUS_POWER_CORE_MASK, powr_cores);
> +
> +	mutex_lock(&asus_armoury.mutex);
> +	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, out_val, &result);
> +	mutex_unlock(&asus_armoury.mutex);
> +
> +	if (err) {
> +		pr_warn("Failed to set CPU core count: %d\n", err);
> +		return err;
> +	}
> +
> +	if (result > 1) {
> +		pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
> +		return -EIO;
> +	}
> +
> +	pr_info("CPU core count changed, reboot required\n");
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +	asus_set_reboot_and_signal_event();
> +
> +	return 0;
> +}
> +
> +static ssize_t cores_performance_min_value_show(struct kobject *kobj,
> +						struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
> +}
> +
> +static ssize_t cores_performance_max_value_show(struct kobject *kobj,
> +						struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
> +}
> +
> +static ssize_t cores_performance_default_value_show(struct kobject *kobj,
> +						    struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
> +}
> +
> +static ssize_t cores_performance_current_value_show(struct kobject *kobj,
> +						    struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
> +}
> +
> +static ssize_t cores_performance_current_value_store(struct kobject *kobj,
> +						     struct kobj_attribute *attr,
> +						     const char *buf, size_t count)
> +{
> +	int err;
> +
> +	err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
> +	if (err)
> +		return err;
> +
> +	return count;
> +}
> +ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
> +		    "Set the max available performance cores");
> +
> +static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> +					       char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
> +}
> +
> +static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> +					       char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
> +}
> +
> +static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
> +						   struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
> +}
> +
> +static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
> +						   struct kobj_attribute *attr, char *buf)
> +{
> +	return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
> +}
> +
> +static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
> +						    struct kobj_attribute *attr, const char *buf,
> +						    size_t count)
> +{
> +	int err;
> +
> +	err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
> +	if (err)
> +		return err;
> +
> +	return count;
> +}
> +ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
> +		    "Set the max available efficiency cores");
> +
>   /* Simple attribute creation */
>   ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
>   		       cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> @@ -625,6 +841,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>   	{ &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
>   	{ &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
>   	{ &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
> +	{ &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
> +	{ &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
>   
>   	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
>   	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> @@ -802,6 +1020,7 @@ static int __init asus_fw_init(void)
>   		return -ENOMEM;
>   
>   	init_rog_tunables(asus_armoury.rog_tunables);
> +	init_max_cpu_cores();
>   
>   	err = asus_fw_attr_add();
>   	if (err)
> diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> index a5f95e806b4b..f400e3af24be 100644
> --- a/drivers/platform/x86/asus-armoury.h
> +++ b/drivers/platform/x86/asus-armoury.h
> @@ -167,6 +167,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
>   		.name = _fsname, .attrs = _attrname##_attrs               \
>   	}
>   
> +/* CPU core attributes need a little different in setup */
> +#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname)              \
> +	__ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1);        \
> +	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
> +	static struct kobj_attribute attr_##_attrname##_current_value = \
> +		__ASUS_ATTR_RW(_attrname, current_value);               \
> +	static struct kobj_attribute attr_##_attrname##_default_value = \
> +		__ASUS_ATTR_RO(_attrname, default_value);               \
> +	static struct kobj_attribute attr_##_attrname##_min_value =     \
> +		__ASUS_ATTR_RO(_attrname, min_value);                   \
> +	static struct kobj_attribute attr_##_attrname##_max_value =     \
> +		__ASUS_ATTR_RO(_attrname, max_value);                   \
> +	static struct kobj_attribute attr_##_attrname##_type =          \
> +		__ASUS_ATTR_RO_AS(type, int_type_show);                 \
> +	static struct attribute *_attrname##_attrs[] = {                \
> +		&attr_##_attrname##_current_value.attr,                 \
> +		&attr_##_attrname##_default_value.attr,                 \
> +		&attr_##_attrname##_min_value.attr,                     \
> +		&attr_##_attrname##_max_value.attr,                     \
> +		&attr_##_attrname##_scalar_increment.attr,              \
> +		&attr_##_attrname##_display_name.attr,                  \
> +		&attr_##_attrname##_type.attr,                          \
> +		NULL                                                    \
> +	};                                                              \
> +	static const struct attribute_group _attrname##_attr_group = {  \
> +		.name = _fsname, .attrs = _attrname##_attrs             \
> +	}
> +
>   /*
>    * ROG PPT attributes need a little different in setup as they
>    * require rog_tunables members.
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index e1aeafdf05d5..8964e601543a 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -134,6 +134,10 @@
>   /* dgpu on/off */
>   #define ASUS_WMI_DEVID_DGPU		0x00090020
>   
> +/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
> +#define ASUS_WMI_DEVID_CORES		0x001200D2
> + /* Maximum Intel E-core and P-core availability */
> +#define ASUS_WMI_DEVID_CORES_MAX	0x001200D3
>   #define ASUS_WMI_DEVID_DGPU_BASE_TGP	0x00120099
>   #define ASUS_WMI_DEVID_DGPU_SET_TGP	0x00120098
>   #define ASUS_WMI_DEVID_APU_MEM		0x000600C1


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26  9:29 ` [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
@ 2024-09-26 15:48   ` Mario Limonciello
  2024-09-26 23:20     ` Luke Jones
  2024-09-26 19:10   ` Markus Elfring
  1 sibling, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 15:48 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: linux-input, bentiss, jikos, platform-driver-x86, ilpo.jarvinen,
	hdegoede, corentin.chary

On 9/26/2024 04:29, Luke D. Jones wrote:
> The fw_attributes_class provides a much cleaner interface to all of the
> attributes introduced to asus-wmi. This patch moves all of these extra

No need to say "this patch".

> attributes over to fw_attributes_class, and shifts the bulk of these
> definitions to a new kernel module to reduce the clutter of asus-wmi
> with the intention of deprecating the asus-wmi attributes in future.
> 
> The work applies only to WMI methods which don't have a clearly defined
> place within the sysfs and as a result ended up lumped together in
> /sys/devices/platform/asus-nb-wmi/ with no standard API.
> 
> Where possible the fw attrs now implement defaults, min, max, scalar,
> choices, etc. As en example dgpu_disable becomes:
> 
> /sys/class/firmware-attributes/asus-armoury/attributes/dgpu_disable/
> ├── current_value
> ├── display_name
> ├── possible_values
> └── type
> 
> as do other attributes.
> 
> The ppt_* based attributes are removed in this initial patch as the
> implementation is somewhat broken due to the WMI methods requiring a
> set of limits on the values accepted (which is not provided by WMI).
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
>   drivers/platform/x86/Kconfig        |  13 +
>   drivers/platform/x86/Makefile       |   1 +
>   drivers/platform/x86/asus-armoury.c | 563 ++++++++++++++++++++++++++++
>   drivers/platform/x86/asus-armoury.h | 146 ++++++++
>   4 files changed, 723 insertions(+)
>   create mode 100644 drivers/platform/x86/asus-armoury.c
>   create mode 100644 drivers/platform/x86/asus-armoury.h
> 
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index 3875abba5a79..dedf66e0d099 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -265,6 +265,19 @@ config ASUS_WIRELESS
>   	  If you choose to compile this driver as a module the module will be
>   	  called asus-wireless.
>   
> +config ASUS_ARMOURY
> +	tristate "ASUS Armoury driver"
> +	depends on ACPI_WMI

I don't think you need to depend on ACPI_WMI directly because ASUS_WMI 
also depends on it.

> +	depends on ASUS_WMI
> +	select FW_ATTR_CLASS
> +	help
> +	  Say Y here if you have a WMI aware Asus machine and would like to use the
> +	  firmware_attributes API to control various settings typically exposed in
> +	  the ASUS Armoury Crate application available on Windows.
> +
> +	  To compile this driver as a module, choose M here: the module will
> +	  be called asus-armoury.
> +
>   config ASUS_WMI
>   	tristate "ASUS WMI Driver"
>   	depends on ACPI_WMI
> diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> index e1b142947067..fe3e7e7dede8 100644
> --- a/drivers/platform/x86/Makefile
> +++ b/drivers/platform/x86/Makefile
> @@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX)	+= apple-gmux.o
>   # ASUS
>   obj-$(CONFIG_ASUS_LAPTOP)	+= asus-laptop.o
>   obj-$(CONFIG_ASUS_WIRELESS)	+= asus-wireless.o
> +obj-$(CONFIG_ASUS_ARMOURY)	+= asus-armoury.o
>   obj-$(CONFIG_ASUS_WMI)		+= asus-wmi.o
>   obj-$(CONFIG_ASUS_NB_WMI)	+= asus-nb-wmi.o
>   obj-$(CONFIG_ASUS_TF103C_DOCK)	+= asus-tf103c-dock.o
> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> new file mode 100644
> index 000000000000..39e422b16b8e
> --- /dev/null
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -0,0 +1,563 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes
> + * class to expose the various WMI functions that many gaming and some
> + * non-gaming ASUS laptops have available.
> + * These typically don't fit anywhere else in the sysfs such as under LED class,
> + * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool.
> + *
> + * Copyright(C) 2010 Intel Corporation.
> + * Copyright(C) 2024-2024 Luke Jones <luke@ljones.dev>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/device.h>
> +#include <linux/dmi.h>
> +#include <linux/errno.h>
> +#include <linux/fs.h>
> +#include <linux/kernel.h>
> +#include <linux/kmod.h>
> +#include <linux/kobject.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_data/x86/asus-wmi.h>
> +#include <linux/types.h>
> +
> +#include "asus-armoury.h"
> +#include "firmware_attributes_class.h"
> +#include "asus-wmi.h"
> +
> +#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
> +
> +#define ASUS_MINI_LED_MODE_MASK 0x03
> +/* Standard modes for devices with only on/off */
> +#define ASUS_MINI_LED_OFF 0x00
> +#define ASUS_MINI_LED_ON 0x01
> +/* Like "on" but the effect is more vibrant or brighter */
> +#define ASUS_MINI_LED_STRONG_MODE 0x02
> +/* New modes for devices with 3 mini-led mode types */
> +#define ASUS_MINI_LED_2024_WEAK 0x00
> +#define ASUS_MINI_LED_2024_STRONG 0x01
> +#define ASUS_MINI_LED_2024_OFF 0x02
> +
> +/* Default limits for tunables available on ASUS ROG laptops */
> +#define PPT_CPU_LIMIT_MIN 5
> +#define PPT_CPU_LIMIT_MAX 150
> +#define PPT_CPU_LIMIT_DEFAULT 80
> +#define PPT_PLATFORM_MIN 5
> +#define PPT_PLATFORM_MAX 100
> +#define PPT_PLATFORM_DEFAULT 80
> +#define NVIDIA_BOOST_MIN 5
> +#define NVIDIA_BOOST_MAX 25
> +#define NVIDIA_TEMP_MIN 75
> +#define NVIDIA_TEMP_MAX 87

Purely for alphabetical order purposes shouldn't NVIDIA_* come before PPT*?

Also can you leave a comment where these default limits come from?

> +
> +static const struct class *fw_attr_class;
> +
> +struct asus_armoury_priv {
> +	struct device *fw_attr_dev;
> +	struct kset *fw_attr_kset;
> +
> +	u32 mini_led_dev_id;
> +	u32 gpu_mux_dev_id;
> +
> +	struct mutex mutex;
> +};
> +
> +static struct asus_armoury_priv asus_armoury = { .mutex = __MUTEX_INITIALIZER(
> +							 asus_armoury.mutex) };
> +
> +struct fw_attrs_group {
> +	bool pending_reboot;
> +};
> +
> +static struct fw_attrs_group fw_attrs = {
> +	.pending_reboot = false,
> +};
> +
> +struct asus_attr_group {
> +	const struct attribute_group *attr_group;
> +	u32 wmi_devid;
> +};
> +
> +static bool asus_wmi_is_present(u32 dev_id)
> +{
> +	u32 retval;
> +	int status;
> +
> +	status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval);
> +	pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
> +
> +	return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);

It seems like you're hiding the potential ACPI failures which could make 
this a bit harder to debug in the future.  What do you think about doing 
it like this:

u32 ret;

if (!asus_wmi_evaluate_method()) {
	pr_debug("acpi_wmi_evaluate_method failed\n");
	return false;
}

return ret & ASUS_WMI_DSDTS_PRESENCE_BIT;

> +}
> +
> +static void asus_set_reboot_and_signal_event(void)
> +{
> +	fw_attrs.pending_reboot = true;
> +	kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE);
> +}
> +
> +static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> +{
> +	return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot);
> +}
> +
> +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> +
> +static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
> +{
> +	return !strcmp(attr->attr.name, "gpu_mux_mode");
> +}
> +
> +/**
> + * attr_int_store() - Generic store function for use with most WMI functions.
> + * @kobj: Pointer to the driver object.
> + * @kobj_attribute: Pointer to the attribute calling this function.
> + * @buf: The buffer to read from, this is parsed to `int` type.
> + * @count:

Missing a description here.

> + * @min: Minimum accepted value. Below this returns -EINVAL.
> + * @max: Maximum accepted value. Above this returns -EINVAL.
> + * @store_value: Pointer to where the parsed value should be stored.
> + * @wmi_dev: The WMI function ID to use.
> + *
> + * The WMI functions available on most ASUS laptops return a 1 as "success", and
> + * a 0 as failed. However some functions can return n > 1 for additional errors.
> + * attr_int_store() currently treats all values which are not 1 as errors, ignoring

IMO; Don't refer to function() in the description.

> + * the possible differences in WMI error returns.
> + *
> + * Returns: Either count, or an error.
> + */
> +static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
> +			      size_t count, u32 min, u32 max, u32 *store_value, u32 wmi_dev)
> +{
> +	u32 result, value;
> +	int err;
> +
> +	err = kstrtouint(buf, 10, &value);
> +	if (err)
> +		return err;
> +
> +	if (value < min || value > max)
> +		return -EINVAL;
> +
> +	err = asus_wmi_set_devstate(wmi_dev, value, &result);
> +	if (err) {
> +		pr_err("Failed to set %s: %d\n", attr->attr.name, err);
> +		return err;
> +	}
> +
> +	if (result != 1) {
> +		pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result);
> +		return -EIO;
> +	}
> +
> +	if (store_value != NULL)
> +		*store_value = value;
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +
> +	if (asus_bios_requires_reboot(attr))
> +		asus_set_reboot_and_signal_event();
> +
> +	return count;
> +}
> +
> +/* Mini-LED mode **************************************************************/
> +static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
> +						struct kobj_attribute *attr, char *buf)
> +{
> +	u32 value;
> +	int err;
> +
> +	err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value);
> +	if (err)
> +		return err;
> +
> +	value &= ASUS_MINI_LED_MODE_MASK;
> +
> +	/*
> +	 * Remap the mode values to match previous generation mini-LED. The last gen
> +	 * WMI 0 == off, while on this version WMI 2 == off (flipped).
> +	 */
> +	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
> +		switch (value) {
> +		case ASUS_MINI_LED_2024_WEAK:
> +			value = ASUS_MINI_LED_ON;
> +			break;
> +		case ASUS_MINI_LED_2024_STRONG:
> +			value = ASUS_MINI_LED_STRONG_MODE;
> +			break;
> +		case ASUS_MINI_LED_2024_OFF:
> +			value = ASUS_MINI_LED_OFF;
> +			break;
> +		}
> +	}
> +
> +	return sysfs_emit(buf, "%u\n", value);
> +}
> +
> +static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
> +						 struct kobj_attribute *attr, const char *buf,
> +						 size_t count)
> +{
> +	int result, err;
> +	u32 mode;
> +
> +	err = kstrtou32(buf, 10, &mode);
> +	if (err)
> +		return err;
> +
> +	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
> +	    mode > ASUS_MINI_LED_ON)
> +		return -EINVAL;
> +	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
> +	    mode > ASUS_MINI_LED_STRONG_MODE)
> +		return -EINVAL;
> +
> +	/*
> +	 * Remap the mode values so expected behaviour is the same as the last
> +	 * generation of mini-LED with 0 == off, 1 == on.
> +	 */
> +	if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
> +		switch (mode) {
> +		case ASUS_MINI_LED_OFF:
> +			mode = ASUS_MINI_LED_2024_OFF;
> +			break;
> +		case ASUS_MINI_LED_ON:
> +			mode = ASUS_MINI_LED_2024_WEAK;
> +			break;
> +		case ASUS_MINI_LED_STRONG_MODE:
> +			mode = ASUS_MINI_LED_2024_STRONG;
> +			break;
> +		}
> +	}
> +
> +	err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result);
> +	if (err) {
> +		pr_warn("Failed to set mini-LED: %d\n", err);
> +		return err;
> +	}
> +
> +	if (result != 1) {
> +		pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
> +		return -EIO;
> +	}
> +
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +
> +	return count;
> +}
> +
> +static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
> +						  struct kobj_attribute *attr, char *buf)
> +{
> +	switch (asus_armoury.mini_led_dev_id) {
> +	case ASUS_WMI_DEVID_MINI_LED_MODE:
> +		return sysfs_emit(buf, "0;1\n");
> +	case ASUS_WMI_DEVID_MINI_LED_MODE2:
> +		return sysfs_emit(buf, "0;1;2\n");
> +	}
> +
> +	return sysfs_emit(buf, "0\n");
> +}
> +
> +ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode");
> +
> +static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj,
> +						struct kobj_attribute *attr, const char *buf,
> +						size_t count)
> +{
> +	int result, err;
> +	u32 optimus;
> +
> +	err = kstrtou32(buf, 10, &optimus);
> +	if (err)
> +		return err;
> +
> +	if (optimus > 1)
> +		return -EINVAL;
> +
> +	if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) {
> +		err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result);
> +		if (err)
> +			return err;
> +		if (result && !optimus) {
> +			err = -ENODEV;
> +			pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %02X %02X %d\n",
> +				result, optimus, err);
> +			return err;
> +		}
> +	}
> +
> +	if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) {
> +		err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result);
> +		if (err)
> +			return err;
> +		if (result && !optimus) {
> +			err = -ENODEV;
> +			pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n",
> +				err);
> +			return err;
> +		}
> +	}
> +
> +	err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result);
> +	if (err) {
> +		pr_err("Failed to set GPU MUX mode: %d\n", err);
> +		return err;
> +	}
> +	/* !1 is considered a fail by ASUS */
> +	if (result != 1) {
> +		pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result);
> +		return -EIO;
> +	}
> +
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +	asus_set_reboot_and_signal_event();
> +
> +	return count;
> +}
> +WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id);
> +ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode");
> +
> +/*
> + * A user may be required to store the value twice, typical store first, then
> + * rescan PCI bus to activate power, then store a second time to save correctly.
> + * The reason for this is that an extra code path in the ACPI is enabled when
> + * the device and bus are powered.
> + */
> +static ssize_t dgpu_disable_current_value_store(struct kobject *kobj,
> +						struct kobj_attribute *attr, const char *buf,
> +						size_t count)
> +{
> +	int result, err;
> +	u32 disable;
> +
> +	err = kstrtou32(buf, 10, &disable);
> +	if (err)
> +		return err;
> +
> +	if (disable > 1)
> +		return -EINVAL;
> +
> +	if (asus_armoury.gpu_mux_dev_id) {
> +		err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
> +		if (err)
> +			return err;
> +		if (!result && disable) {
> +			err = -ENODEV;
> +			pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
> +			return err;
> +		}
> +	}
> +
> +	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
> +	if (err) {
> +		pr_warn("Failed to set dGPU disable: %d\n", err);
> +		return err;
> +	}
> +
> +	if (result != 1) {
> +		pr_warn("Failed to set dGPU disable (result): 0x%x\n", result);
> +		return -EIO;
> +	}
> +
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +
> +	return count;
> +}
> +WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU);
> +ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU");
> +
> +/* The ACPI call to enable the eGPU also disables the internal dGPU */
> +static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> +					       const char *buf, size_t count)
> +{
> +	int result, err;
> +	u32 enable;
> +
> +	err = kstrtou32(buf, 10, &enable);
> +	if (err)
> +		return err;
> +
> +	if (enable > 1)
> +		return -EINVAL;
> +
> +	err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result);
> +	if (err) {
> +		pr_warn("Failed to get eGPU connection status: %d\n", err);
> +		return err;
> +	}
> +
> +	if (asus_armoury.gpu_mux_dev_id) {
> +		err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
> +		if (err) {
> +			pr_warn("Failed to get GPU MUX status: %d\n", result);
> +			return result;
> +		}
> +		if (!result && enable) {
> +			err = -ENODEV;
> +			pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
> +			return err;
> +		}
> +	}
> +
> +	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
> +	if (err) {
> +		pr_warn("Failed to set eGPU state: %d\n", err);
> +		return err;
> +	}
> +
> +	if (result != 1) {
> +		pr_warn("Failed to set eGPU state (retval): 0x%x\n", result);
> +		return -EIO;
> +	}
> +
> +	sysfs_notify(kobj, NULL, attr->attr.name);
> +
> +	return count;
> +}
> +WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
> +ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
> +
> +/* Simple attribute creation */
> +ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
> +		       "Show the current mode of charging");
> +
> +ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND,
> +		   "Set the boot POST sound");
> +ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
> +		   "Set MCU powersaving mode");
> +ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
> +		   "Set the panel refresh overdrive");
> +ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
> +		   "Show the eGPU connection status");
> +
> +/* If an attribute does not require any special case handling add it here */
> +static const struct asus_attr_group armoury_attr_groups[] = {
> +	{ &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED },
> +	{ &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
> +	{ &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
> +
> +	{ &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
> +	{ &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> +	{ &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
> +	{ &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
> +};
> +
> +static int asus_fw_attr_add(void)
> +{
> +	int err;
> +
> +	err = fw_attributes_class_get(&fw_attr_class);
> +	if (err)
> +		goto fail_class_created;

Is that right?  If you fail to get the class shouldn't you just return 
an error code?

> +
> +	asus_armoury.fw_attr_dev =
> +		device_create(fw_attr_class, NULL, MKDEV(0, 0), NULL, "%s", DRIVER_NAME);
> +
> +	if (IS_ERR(asus_armoury.fw_attr_dev)) {
> +		err = PTR_ERR(asus_armoury.fw_attr_dev);
> +		goto fail_class_created;
> +	}
> +
> +	asus_armoury.fw_attr_kset =
> +		kset_create_and_add("attributes", NULL, &asus_armoury.fw_attr_dev->kobj);
> +	if (!asus_armoury.fw_attr_dev) {
> +		err = -ENOMEM;
> +		pr_debug("Failed to create and add attributes\n");
> +		goto err_destroy_classdev;
> +	}
> +
> +	err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
> +	if (err) {
> +		pr_warn("Failed to create sysfs level attributes\n");
> +		goto fail_class_created;
> +	}
> +
> +	err = 0;
This seems unnecessary.

> +	asus_armoury.mini_led_dev_id = 0;
> +	if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
> +		asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
> +		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> +					 &mini_led_mode_attr_group);
> +	} else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
> +		asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
> +		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> +					 &mini_led_mode_attr_group);
> +	}
> +	if (err)
> +		pr_warn("Failed to create sysfs-group for mini_led\n");

Shouldn't you fail and clean up here?

> +
> +	err = 0;

Assuming you follow my above comment this is unnecessary.

> +	asus_armoury.gpu_mux_dev_id = 0;
> +	if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) {
> +		asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX;
> +		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> +					 &gpu_mux_mode_attr_group);
> +	} else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) {
> +		asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO;
> +		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> +					 &gpu_mux_mode_attr_group);
> +	}
> +	if (err)
> +		pr_warn("Failed to create sysfs-group for gpu_mux\n");

Shouldn't you fail and clean up here?

> +
> +	for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) {
> +		if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid))
> +			continue;
> +
> +		err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> +					 armoury_attr_groups[i].attr_group);
> +		if (err)
> +			pr_warn("Failed to create sysfs-group for %s\n",
> +				armoury_attr_groups[i].attr_group->name);

Shouldn't you fail and clean up here?

> +		else
> +			pr_debug("Created sysfs-group for %s\n",
> +				 armoury_attr_groups[i].attr_group->name);
> +	}
> +
> +	return 0;
> +
> +err_destroy_classdev:
> +	device_destroy(fw_attr_class, MKDEV(0, 0));
> +
> +fail_class_created:
> +	fw_attributes_class_put();
> +	return err;
> +}
> +
> +/* Init / exit ****************************************************************/
> +
> +static int __init asus_fw_init(void)
> +{
> +	int err;
> +
> +	fw_attrs.pending_reboot = false;

Isn't it already initialized to false?

> +
> +	err = asus_fw_attr_add();
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static void __exit asus_fw_exit(void)
> +{
> +	mutex_lock(&asus_armoury.mutex);

I think you should be using this mutex more.  For example what if an 
attribute is being written while the module is unloaded?

> +
> +	sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
> +	kset_unregister(asus_armoury.fw_attr_kset);
> +	device_destroy(fw_attr_class, MKDEV(0, 0));
> +	fw_attributes_class_put();
> +
> +	mutex_unlock(&asus_armoury.mutex);
> +}
> +
> +module_init(asus_fw_init);
> +module_exit(asus_fw_exit);
> +
> +MODULE_IMPORT_NS(ASUS_WMI);
> +MODULE_AUTHOR("Luke Jones <luke@ljones.dev>");
> +MODULE_DESCRIPTION("ASUS BIOS Configuration Driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID);
> diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> new file mode 100644
> index 000000000000..b99fd136abf1
> --- /dev/null
> +++ b/drivers/platform/x86/asus-armoury.h
> @@ -0,0 +1,146 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Definitions for kernel modules using asus-armoury driver
> + *
> + *  Copyright (c) 2024 Luke Jones <luke@ljones.dev>
> + */
> +
> +#ifndef _ASUS_BIOSCFG_H_
> +#define _ASUS_BIOSCFG_H_
> +
> +#include <linux/types.h>
> +#include <linux/platform_device.h>
> +
> +#define DRIVER_NAME "asus-armoury"
> +
> +static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
> +			      const char *buf, size_t count, u32 min, u32 max,
> +			      u32 *store_value, u32 wmi_dev);
> +
> +static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> +			      char *buf)
> +{
> +	return sysfs_emit(buf, "enumeration\n");
> +}
> +
> +#define __ASUS_ATTR_RO(_func, _name)                                  \
> +	{                                                             \
> +		.attr = { .name = __stringify(_name), .mode = 0444 }, \
> +		.show = _func##_##_name##_show,                       \
> +	}
> +
> +#define __ASUS_ATTR_RO_AS(_name, _show)                               \
> +	{                                                             \
> +		.attr = { .name = __stringify(_name), .mode = 0444 }, \
> +		.show = _show,                                        \
> +	}
> +
> +#define __ASUS_ATTR_RW(_func, _name) \
> +	__ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
> +
> +#define __WMI_STORE_INT(_attr, _min, _max, _wmi)                          \
> +	static ssize_t _attr##_store(struct kobject *kobj,                \
> +				     struct kobj_attribute *attr,         \
> +				     const char *buf, size_t count)       \
> +	{                                                                 \
> +		return attr_int_store(kobj, attr, buf, count, _min, _max, \
> +				      NULL, _wmi);                        \
> +	}
> +
> +#define WMI_SHOW_INT(_attr, _fmt, _wmi)                                     \
> +	static ssize_t _attr##_show(struct kobject *kobj,                   \
> +				    struct kobj_attribute *attr, char *buf) \
> +	{                                                                   \
> +		u32 result;                                                 \
> +		int err;                                                    \
> +		err = asus_wmi_get_devstate_dsts(_wmi, &result);            \
> +		if (err)                                                    \
> +			return err;                                         \
> +		return sysfs_emit(buf, _fmt,                                \
> +				  result & ~ASUS_WMI_DSTS_PRESENCE_BIT);    \
> +	}
> +
> +/* Create functions and attributes for use in other macros or on their own */
> +
> +#define __ATTR_CURRENT_INT_RO(_attr, _wmi)                          \
> +	WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
> +	static struct kobj_attribute attr_##_attr##_current_value = \
> +		__ASUS_ATTR_RO(_attr, current_value)
> +
> +#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi)            \
> +	__WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \
> +	WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
> +	static struct kobj_attribute attr_##_attr##_current_value = \
> +		__ASUS_ATTR_RW(_attr, current_value)
> +
> +/* Shows a formatted static variable */
> +#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                         \
> +	static ssize_t _attrname##_##_prop##_show(                            \
> +		struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> +	{                                                                     \
> +		return sysfs_emit(buf, _fmt, _val);                           \
> +	}                                                                     \
> +	static struct kobj_attribute attr_##_attrname##_##_prop =             \
> +		__ASUS_ATTR_RO(_attrname, _prop)
> +
> +/* Boolean style enumeration, base macro. Requires adding show/store */
> +#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)     \
> +	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
> +	__ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
> +	static struct kobj_attribute attr_##_attrname##_type =          \
> +		__ASUS_ATTR_RO_AS(type, enum_type_show);                \
> +	static struct attribute *_attrname##_attrs[] = {                \
> +		&attr_##_attrname##_current_value.attr,                 \
> +		&attr_##_attrname##_display_name.attr,                  \
> +		&attr_##_attrname##_possible_values.attr,               \
> +		&attr_##_attrname##_type.attr,                          \
> +		NULL                                                    \
> +	};                                                              \
> +	static const struct attribute_group _attrname##_attr_group = {  \
> +		.name = _fsname, .attrs = _attrname##_attrs             \
> +	}
> +
> +#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
> +	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                 \
> +	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> +
> +#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \
> +	__ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi);           \
> +	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> +
> +/*
> + * Requires <name>_current_value_show(), <name>_current_value_show()
> + */
> +#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname)           \
> +	static struct kobj_attribute attr_##_attrname##_current_value = \
> +		__ASUS_ATTR_RW(_attrname, current_value);               \
> +	__ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> +
> +#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \
> +	__ATTR_CURRENT_INT_RO(_attrname, _wmi);                                \
> +	__ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)
> +
> +/*
> + * Requires <name>_current_value_show(), <name>_current_value_show()
> + * and <name>_possible_values_show()
> + */
> +#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname)             \
> +	__ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);      \
> +	static struct kobj_attribute attr_##_attrname##_current_value =   \
> +		__ASUS_ATTR_RW(_attrname, current_value);                 \
> +	static struct kobj_attribute attr_##_attrname##_possible_values = \
> +		__ASUS_ATTR_RO(_attrname, possible_values);               \
> +	static struct kobj_attribute attr_##_attrname##_type =            \
> +		__ASUS_ATTR_RO_AS(type, enum_type_show);                  \
> +	static struct attribute *_attrname##_attrs[] = {                  \
> +		&attr_##_attrname##_current_value.attr,                   \
> +		&attr_##_attrname##_display_name.attr,                    \
> +		&attr_##_attrname##_possible_values.attr,                 \
> +		&attr_##_attrname##_type.attr,                            \
> +		NULL                                                      \
> +	};                                                                \
> +	static const struct attribute_group _attrname##_attr_group = {    \
> +		.name = _fsname, .attrs = _attrname##_attrs               \
> +	}
> +
> +#endif /* _ASUS_BIOSCFG_H_ */


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26  9:29 ` [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
  2024-09-26 15:48   ` Mario Limonciello
@ 2024-09-26 19:10   ` Markus Elfring
  2024-09-26 21:50     ` Luke Jones
  1 sibling, 1 reply; 39+ messages in thread
From: Markus Elfring @ 2024-09-26 19:10 UTC (permalink / raw)
  To: Luke D. Jones, platform-driver-x86, linux-input,
	Benjamin Tissoires, Corentin Chary, Hans de Goede,
	Ilpo Järvinen, Jiri Kosina, Mario Limonciello
  Cc: LKML> +++ b/drivers/platform/x86/asus-armoury.h
> @@ -0,0 +1,146 @@
> +#ifndef _ASUS_BIOSCFG_H_
> +#define _ASUS_BIOSCFG_H_
…

I suggest to omit leading underscores from such identifiers.
https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier

Regards,
Markus

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 0/9] platform/x86: introduce asus-armoury driver
  2024-09-26 14:50 ` [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Mario Limonciello
@ 2024-09-26 21:44   ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-26 21:44 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Fri, 27 Sep 2024, at 2:50 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > his is the first major patch I've ever done with the intention of
> 
> s/his/This/
> 
> > introducing a new module, so it's highly likely I've made some mistakes
> > or misunderstood something.
> > 
> > TL;DR:
> > 1. introduce new module to contain bios attributes, using fw_attributes_class
> > 2. deprecate all possible attributes from asus-wmi that were added ad-hoc
> > 3. remove those in the next LTS cycle
> > 
> > The idea for this originates from a conversation with Mario Limonciello
> > https://lore.kernel.org/platform-driver-x86/371d4109-a3bb-4c3b-802f-4ec27a945c99@amd.com/
> > 
> > It is without a doubt much cleaner to use, easier to discover, and the
> > API is well defined as opposed to the random clutter of attributes I had
> > been placing in the platform sysfs.
> > 
> > There is some discussion on-going regarding the way tuning knobs such as
> > the PPT_* should work with platform_profile. This may result in the creation
> > of an extra profile type "Custom" to signify that the user has adjusted
> > things away from the defaults used by profiles such as "balanced" or "quiet".
> 
> Yeah this is under discussion on my RFC patch series.  Based on the 
> outcome of that we can modify asus-armoury later on for it.

Perfect

> > 
> > Regards,
> > Luke
> > 
> > Changelog:
> > - v1
> >    - Initial submission
> > - v2
> >    - Too many changes to list, but all concerns raised in previous submission addressed.
> >    - History: https://lore.kernel.org/platform-driver-x86/20240716051612.64842-1-luke@ljones.dev/
> > - v3
> >    - All concerns addressed.
> >    - History: https://lore.kernel.org/platform-driver-x86/20240806020747.365042-1-luke@ljones.dev/
> > - v4
> >    - Use EXPORT_SYMBOL_NS_GPL() for the symbols required in this patch series
> >    - Add patch for hid-asus due to the use of EXPORT_SYMBOL_NS_GPL()
> >    - Split the PPT knobs out to a separate patch
> >    - Split the hd_panel setting out to a new patch
> >    - Clarify some of APU MEM configuration and convert int to hex
> >    - Rename deprecated Kconfig option to ASUS_WMI_DEPRECATED_ATTRS
> >    - Fixup cyclic dependency in Kconfig
> > 
> > Luke D. Jones (9):
> >    platform/x86: asus-wmi: export symbols used for read/write WMI
> >    hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI)
> >    platform/x86: asus-armoury: move existing tunings to asus-armoury
> >      module
> >    platform/x86: asus-armoury: add panel_hd_mode attribute
> >    platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
> >    platform/x86: asus-armoury: add dgpu tgp control
> >    platform/x86: asus-armoury: add apu-mem control support
> >    platform/x86: asus-armoury: add core count control
> >    platform/x86: asus-wmi: deprecate bios features
> > 
> >   .../ABI/testing/sysfs-platform-asus-wmi       |   17 +
> >   drivers/hid/hid-asus.c                        |    1 +
> >   drivers/platform/x86/Kconfig                  |   22 +
> >   drivers/platform/x86/Makefile                 |    1 +
> >   drivers/platform/x86/asus-armoury.c           | 1051 +++++++++++++++++
> >   drivers/platform/x86/asus-armoury.h           |  257 ++++
> >   drivers/platform/x86/asus-wmi.c               |  185 ++-
> >   include/linux/platform_data/x86/asus-wmi.h    |   19 +
> >   8 files changed, 1520 insertions(+), 33 deletions(-)
> >   create mode 100644 drivers/platform/x86/asus-armoury.c
> >   create mode 100644 drivers/platform/x86/asus-armoury.h
> > 
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 8/9] platform/x86: asus-armoury: add core count control
  2024-09-26 15:30   ` Mario Limonciello
@ 2024-09-26 21:47     ` Luke Jones
  2024-09-26 22:02       ` Mario Limonciello
  0 siblings, 1 reply; 39+ messages in thread
From: Luke Jones @ 2024-09-26 21:47 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

Resend, sorry. My email client defaults to HTML

On Fri, 27 Sep 2024, at 3:30 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > Implement Intel core enablement under the asus-armoury module using the
> > fw_attributes class.
> > 
> > This allows users to enable or disable preformance or efficiency cores
> > depending on their requirements. After change a reboot is required.
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> > ---
> >   drivers/platform/x86/asus-armoury.c        | 219 +++++++++++++++++++++
> >   drivers/platform/x86/asus-armoury.h        |  28 +++
> >   include/linux/platform_data/x86/asus-wmi.h |   4 +
> >   3 files changed, 251 insertions(+)
> > 
> > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> > index a0022dcee3a4..ce1facb40bd5 100644
> > --- a/drivers/platform/x86/asus-armoury.c
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -40,6 +40,21 @@
> >   #define ASUS_MINI_LED_2024_STRONG 0x01
> >   #define ASUS_MINI_LED_2024_OFF 0x02
> >   
> > +#define ASUS_POWER_CORE_MASK GENMASK(15, 8)
> > +#define ASUS_PERF_CORE_MASK GENMASK(7, 0)
> > +
> > +enum cpu_core_type {
> > + CPU_CORE_PERF = 0,
> > + CPU_CORE_POWER,
> > +};
> > +
> > +enum cpu_core_value {
> > + CPU_CORE_DEFAULT = 0,
> > + CPU_CORE_MIN,
> > + CPU_CORE_MAX,
> > + CPU_CORE_CURRENT,
> > +};
> > +
> >   /* Default limits for tunables available on ASUS ROG laptops */
> >   #define PPT_CPU_LIMIT_MIN 5
> >   #define PPT_CPU_LIMIT_MAX 150
> > @@ -85,6 +100,13 @@ struct rog_tunables {
> >   u32 dgpu_tgp_min;
> >   u32 dgpu_tgp_max;
> >   u32 dgpu_tgp;
> > +
> > + u32 cur_perf_cores;
> > + u32 min_perf_cores;
> > + u32 max_perf_cores;
> > + u32 cur_power_cores;
> > + u32 min_power_cores;
> > + u32 max_power_cores;
> >   };
> >   
> >   static const struct class *fw_attr_class;
> > @@ -143,6 +165,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> >   static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
> >   {
> >   return !strcmp(attr->attr.name, "gpu_mux_mode") ||
> > +        !strcmp(attr->attr.name, "cores_performance") ||
> > +        !strcmp(attr->attr.name, "cores_efficiency") ||
> >          !strcmp(attr->attr.name, "panel_hd_mode");
> >   }
> >   
> > @@ -569,6 +593,198 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at
> >   }
> >   ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
> >   
> > +static int init_max_cpu_cores(void)
> > +{
> > + u32 cores;
> > + int err;
> > +
> > + asus_armoury.rog_tunables->min_perf_cores = 4;
> > + asus_armoury.rog_tunables->max_perf_cores = 4;
> > + asus_armoury.rog_tunables->cur_perf_cores = 4;
> > + asus_armoury.rog_tunables->min_power_cores = 0;
> > + asus_armoury.rog_tunables->max_power_cores = 8;
> > + asus_armoury.rog_tunables->cur_power_cores = 8;
> 
> This seems like it's going to be dependent upon "specific" CPU SKU, no?

It is yeah. I was trying to set some sort of default but forgot about it after the fact.

> If you can't detect the bounds from the WMI API I think it would be 
> smarter to use the CPU vendor specific CPUID/MSR APIs to discover the 
> topology and how many cores of the different types exist.

Thinking about it now I would rather set it as an error and disable the ability to set cores. What do you think?

> Furthermore what about LP cores?  I guess those can't be turned and off 
> from this API?

power/efficiency cores? They can be.

> > +
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
> > + if (err)
> > + return err;
> > +
> > + cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
> > + asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
> > + asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
> > +
> > + cores = 0;
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
> > + if (err)
> > + return err;
> > +
> > + asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
> > + asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
> > +
> > + return 0;
> > +}
> > +
> > +static ssize_t cores_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf,
> > + enum cpu_core_type core_type, enum cpu_core_value core_value)
> > +{
> > + u32 cores;
> > +
> > + switch (core_value) {
> > + case CPU_CORE_DEFAULT:
> > + case CPU_CORE_MAX:
> > + if (core_type == CPU_CORE_PERF)
> > + return sysfs_emit(buf, "%d\n",
> > +   asus_armoury.rog_tunables->max_perf_cores);
> > + else
> > + return sysfs_emit(buf, "%d\n",
> > +   asus_armoury.rog_tunables->max_power_cores);
> > + case CPU_CORE_MIN:
> > + if (core_type == CPU_CORE_PERF)
> > + return sysfs_emit(buf, "%d\n",
> > +   asus_armoury.rog_tunables->min_perf_cores);
> > + else
> > + return sysfs_emit(buf, "%d\n",
> > +   asus_armoury.rog_tunables->min_power_cores);
> > + default:
> > + break;
> > + }
> > +
> > + if (core_type == CPU_CORE_PERF)
> > + cores = asus_armoury.rog_tunables->cur_perf_cores;
> > + else
> > + cores = asus_armoury.rog_tunables->cur_power_cores;
> > +
> > + return sysfs_emit(buf, "%d\n", cores);
> > +}
> > +
> > +static ssize_t cores_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> > + const char *buf, enum cpu_core_type core_type)
> > +{
> > + int result, err;
> > + u32 new_cores, perf_cores, powr_cores, out_val, min, max;
> > +
> > + result = kstrtou32(buf, 10, &new_cores);
> > + if (result)
> > + return result;
> > +
> > + if (core_type == CPU_CORE_PERF) {
> > + perf_cores = new_cores;
> > + powr_cores = out_val = asus_armoury.rog_tunables->cur_power_cores;
> > + min = asus_armoury.rog_tunables->min_perf_cores;
> > + max = asus_armoury.rog_tunables->max_perf_cores;
> > + } else {
> > + perf_cores = asus_armoury.rog_tunables->cur_perf_cores;
> > + powr_cores = out_val = new_cores;
> > + min = asus_armoury.rog_tunables->min_power_cores;
> > + max = asus_armoury.rog_tunables->max_power_cores;
> > + }
> > +
> > + if (new_cores < min || new_cores > max)
> > + return -EINVAL;
> > +
> > + out_val = 0;
> > + out_val |= FIELD_PREP(ASUS_PERF_CORE_MASK, perf_cores);
> > + out_val |= FIELD_PREP(ASUS_POWER_CORE_MASK, powr_cores);
> > +
> > + mutex_lock(&asus_armoury.mutex);
> > + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, out_val, &result);
> > + mutex_unlock(&asus_armoury.mutex);
> > +
> > + if (err) {
> > + pr_warn("Failed to set CPU core count: %d\n", err);
> > + return err;
> > + }
> > +
> > + if (result > 1) {
> > + pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
> > + return -EIO;
> > + }
> > +
> > + pr_info("CPU core count changed, reboot required\n");
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > + asus_set_reboot_and_signal_event();
> > +
> > + return 0;
> > +}
> > +
> > +static ssize_t cores_performance_min_value_show(struct kobject *kobj,
> > + struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
> > +}
> > +
> > +static ssize_t cores_performance_max_value_show(struct kobject *kobj,
> > + struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
> > +}
> > +
> > +static ssize_t cores_performance_default_value_show(struct kobject *kobj,
> > +     struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
> > +}
> > +
> > +static ssize_t cores_performance_current_value_show(struct kobject *kobj,
> > +     struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
> > +}
> > +
> > +static ssize_t cores_performance_current_value_store(struct kobject *kobj,
> > +      struct kobj_attribute *attr,
> > +      const char *buf, size_t count)
> > +{
> > + int err;
> > +
> > + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
> > + if (err)
> > + return err;
> > +
> > + return count;
> > +}
> > +ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
> > +     "Set the max available performance cores");
> > +
> > +static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +        char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
> > +}
> > +
> > +static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +        char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
> > +}
> > +
> > +static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
> > +    struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
> > +}
> > +
> > +static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
> > +    struct kobj_attribute *attr, char *buf)
> > +{
> > + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
> > +}
> > +
> > +static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
> > +     struct kobj_attribute *attr, const char *buf,
> > +     size_t count)
> > +{
> > + int err;
> > +
> > + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
> > + if (err)
> > + return err;
> > +
> > + return count;
> > +}
> > +ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
> > +     "Set the max available efficiency cores");
> > +
> >   /* Simple attribute creation */
> >   ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
> >          cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> > @@ -625,6 +841,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
> >   { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
> >   { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
> >   { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
> > + { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
> > + { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
> >   
> >   { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
> >   { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> > @@ -802,6 +1020,7 @@ static int __init asus_fw_init(void)
> >   return -ENOMEM;
> >   
> >   init_rog_tunables(asus_armoury.rog_tunables);
> > + init_max_cpu_cores();
> >   
> >   err = asus_fw_attr_add();
> >   if (err)
> > diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> > index a5f95e806b4b..f400e3af24be 100644
> > --- a/drivers/platform/x86/asus-armoury.h
> > +++ b/drivers/platform/x86/asus-armoury.h
> > @@ -167,6 +167,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> >   .name = _fsname, .attrs = _attrname##_attrs               \
> >   }
> >   
> > +/* CPU core attributes need a little different in setup */
> > +#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname)              \
> > + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1);        \
> > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
> > + static struct kobj_attribute attr_##_attrname##_current_value = \
> > + __ASUS_ATTR_RW(_attrname, current_value);               \
> > + static struct kobj_attribute attr_##_attrname##_default_value = \
> > + __ASUS_ATTR_RO(_attrname, default_value);               \
> > + static struct kobj_attribute attr_##_attrname##_min_value =     \
> > + __ASUS_ATTR_RO(_attrname, min_value);                   \
> > + static struct kobj_attribute attr_##_attrname##_max_value =     \
> > + __ASUS_ATTR_RO(_attrname, max_value);                   \
> > + static struct kobj_attribute attr_##_attrname##_type =          \
> > + __ASUS_ATTR_RO_AS(type, int_type_show);                 \
> > + static struct attribute *_attrname##_attrs[] = {                \
> > + &attr_##_attrname##_current_value.attr,                 \
> > + &attr_##_attrname##_default_value.attr,                 \
> > + &attr_##_attrname##_min_value.attr,                     \
> > + &attr_##_attrname##_max_value.attr,                     \
> > + &attr_##_attrname##_scalar_increment.attr,              \
> > + &attr_##_attrname##_display_name.attr,                  \
> > + &attr_##_attrname##_type.attr,                          \
> > + NULL                                                    \
> > + };                                                              \
> > + static const struct attribute_group _attrname##_attr_group = {  \
> > + .name = _fsname, .attrs = _attrname##_attrs             \
> > + }
> > +
> >   /*
> >    * ROG PPT attributes need a little different in setup as they
> >    * require rog_tunables members.
> > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> > index e1aeafdf05d5..8964e601543a 100644
> > --- a/include/linux/platform_data/x86/asus-wmi.h
> > +++ b/include/linux/platform_data/x86/asus-wmi.h
> > @@ -134,6 +134,10 @@
> >   /* dgpu on/off */
> >   #define ASUS_WMI_DEVID_DGPU 0x00090020
> >   
> > +/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
> > +#define ASUS_WMI_DEVID_CORES 0x001200D2
> > + /* Maximum Intel E-core and P-core availability */
> > +#define ASUS_WMI_DEVID_CORES_MAX 0x001200D3
> >   #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
> >   #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
> >   #define ASUS_WMI_DEVID_APU_MEM 0x000600C1
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26 19:10   ` Markus Elfring
@ 2024-09-26 21:50     ` Luke Jones
  2024-09-27  6:09       ` [v4 " Markus Elfring
  0 siblings, 1 reply; 39+ messages in thread
From: Luke Jones @ 2024-09-26 21:50 UTC (permalink / raw)
  To: Markus Elfring, platform-driver-x86, linux-input,
	Benjamin Tissoires, Corentin Chary, Hans de Goede,
	Ilpo Järvinen, Jiri Kosina, Mario Limonciello
  Cc: LKML



On Fri, 27 Sep 2024, at 7:10 AM, Markus Elfring wrote:
> …
> > +++ b/drivers/platform/x86/asus-armoury.h
> > @@ -0,0 +1,146 @@
> …
> > +#ifndef _ASUS_BIOSCFG_H_
> > +#define _ASUS_BIOSCFG_H_
> …
> 
> I suggest to omit leading underscores from such identifiers.
> https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier

Hi Markus,

the link is C standard, not kernel C right?
Pretty much everything I look at in the kernel seems to use the leading underscores.

Regards,
Luke.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 8/9] platform/x86: asus-armoury: add core count control
  2024-09-26 21:47     ` Luke Jones
@ 2024-09-26 22:02       ` Mario Limonciello
  2024-09-29  7:00         ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-26 22:02 UTC (permalink / raw)
  To: Luke Jones, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On 9/26/2024 16:47, Luke Jones wrote:
> Resend, sorry. My email client defaults to HTML
> 
> On Fri, 27 Sep 2024, at 3:30 AM, Mario Limonciello wrote:
>> On 9/26/2024 04:29, Luke D. Jones wrote:
>>> Implement Intel core enablement under the asus-armoury module using the
>>> fw_attributes class.
>>>
>>> This allows users to enable or disable preformance or efficiency cores
>>> depending on their requirements. After change a reboot is required.
>>>
>>> Signed-off-by: Luke D. Jones <luke@ljones.dev>
>>> ---
>>>    drivers/platform/x86/asus-armoury.c        | 219 +++++++++++++++++++++
>>>    drivers/platform/x86/asus-armoury.h        |  28 +++
>>>    include/linux/platform_data/x86/asus-wmi.h |   4 +
>>>    3 files changed, 251 insertions(+)
>>>
>>> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
>>> index a0022dcee3a4..ce1facb40bd5 100644
>>> --- a/drivers/platform/x86/asus-armoury.c
>>> +++ b/drivers/platform/x86/asus-armoury.c
>>> @@ -40,6 +40,21 @@
>>>    #define ASUS_MINI_LED_2024_STRONG 0x01
>>>    #define ASUS_MINI_LED_2024_OFF 0x02
>>>    
>>> +#define ASUS_POWER_CORE_MASK GENMASK(15, 8)
>>> +#define ASUS_PERF_CORE_MASK GENMASK(7, 0)
>>> +
>>> +enum cpu_core_type {
>>> + CPU_CORE_PERF = 0,
>>> + CPU_CORE_POWER,
>>> +};
>>> +
>>> +enum cpu_core_value {
>>> + CPU_CORE_DEFAULT = 0,
>>> + CPU_CORE_MIN,
>>> + CPU_CORE_MAX,
>>> + CPU_CORE_CURRENT,
>>> +};
>>> +
>>>    /* Default limits for tunables available on ASUS ROG laptops */
>>>    #define PPT_CPU_LIMIT_MIN 5
>>>    #define PPT_CPU_LIMIT_MAX 150
>>> @@ -85,6 +100,13 @@ struct rog_tunables {
>>>    u32 dgpu_tgp_min;
>>>    u32 dgpu_tgp_max;
>>>    u32 dgpu_tgp;
>>> +
>>> + u32 cur_perf_cores;
>>> + u32 min_perf_cores;
>>> + u32 max_perf_cores;
>>> + u32 cur_power_cores;
>>> + u32 min_power_cores;
>>> + u32 max_power_cores;
>>>    };
>>>    
>>>    static const struct class *fw_attr_class;
>>> @@ -143,6 +165,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
>>>    static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
>>>    {
>>>    return !strcmp(attr->attr.name, "gpu_mux_mode") ||
>>> +        !strcmp(attr->attr.name, "cores_performance") ||
>>> +        !strcmp(attr->attr.name, "cores_efficiency") ||
>>>           !strcmp(attr->attr.name, "panel_hd_mode");
>>>    }
>>>    
>>> @@ -569,6 +593,198 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at
>>>    }
>>>    ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
>>>    
>>> +static int init_max_cpu_cores(void)
>>> +{
>>> + u32 cores;
>>> + int err;
>>> +
>>> + asus_armoury.rog_tunables->min_perf_cores = 4;
>>> + asus_armoury.rog_tunables->max_perf_cores = 4;
>>> + asus_armoury.rog_tunables->cur_perf_cores = 4;
>>> + asus_armoury.rog_tunables->min_power_cores = 0;
>>> + asus_armoury.rog_tunables->max_power_cores = 8;
>>> + asus_armoury.rog_tunables->cur_power_cores = 8;
>>
>> This seems like it's going to be dependent upon "specific" CPU SKU, no?
> 
> It is yeah. I was trying to set some sort of default but forgot about it after the fact.
> 
>> If you can't detect the bounds from the WMI API I think it would be
>> smarter to use the CPU vendor specific CPUID/MSR APIs to discover the
>> topology and how many cores of the different types exist.
> 
> Thinking about it now I would rather set it as an error and disable the ability to set cores. What do you think?

Seems fine to me.  Just make sure you mention it's intended behavior in 
a comment somewhere if it's not obvious.

> 
>> Furthermore what about LP cores?  I guess those can't be turned and off
>> from this API?
> 
> power/efficiency cores? They can be.

Intel has 3 core types on some products.  "Performance", "efficiency" 
and "low power".

I don't know a lot about them, I just want to make sure you do so you 
don't back yourself into a corner on API design.

> 
>>> +
>>> + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
>>> + if (err)
>>> + return err;
>>> +
>>> + cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
>>> + asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
>>> + asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
>>> +
>>> + cores = 0;
>>> + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
>>> + if (err)
>>> + return err;
>>> +
>>> + asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
>>> + asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static ssize_t cores_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf,
>>> + enum cpu_core_type core_type, enum cpu_core_value core_value)
>>> +{
>>> + u32 cores;
>>> +
>>> + switch (core_value) {
>>> + case CPU_CORE_DEFAULT:
>>> + case CPU_CORE_MAX:
>>> + if (core_type == CPU_CORE_PERF)
>>> + return sysfs_emit(buf, "%d\n",
>>> +   asus_armoury.rog_tunables->max_perf_cores);
>>> + else
>>> + return sysfs_emit(buf, "%d\n",
>>> +   asus_armoury.rog_tunables->max_power_cores);
>>> + case CPU_CORE_MIN:
>>> + if (core_type == CPU_CORE_PERF)
>>> + return sysfs_emit(buf, "%d\n",
>>> +   asus_armoury.rog_tunables->min_perf_cores);
>>> + else
>>> + return sysfs_emit(buf, "%d\n",
>>> +   asus_armoury.rog_tunables->min_power_cores);
>>> + default:
>>> + break;
>>> + }
>>> +
>>> + if (core_type == CPU_CORE_PERF)
>>> + cores = asus_armoury.rog_tunables->cur_perf_cores;
>>> + else
>>> + cores = asus_armoury.rog_tunables->cur_power_cores;
>>> +
>>> + return sysfs_emit(buf, "%d\n", cores);
>>> +}
>>> +
>>> +static ssize_t cores_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
>>> + const char *buf, enum cpu_core_type core_type)
>>> +{
>>> + int result, err;
>>> + u32 new_cores, perf_cores, powr_cores, out_val, min, max;
>>> +
>>> + result = kstrtou32(buf, 10, &new_cores);
>>> + if (result)
>>> + return result;
>>> +
>>> + if (core_type == CPU_CORE_PERF) {
>>> + perf_cores = new_cores;
>>> + powr_cores = out_val = asus_armoury.rog_tunables->cur_power_cores;
>>> + min = asus_armoury.rog_tunables->min_perf_cores;
>>> + max = asus_armoury.rog_tunables->max_perf_cores;
>>> + } else {
>>> + perf_cores = asus_armoury.rog_tunables->cur_perf_cores;
>>> + powr_cores = out_val = new_cores;
>>> + min = asus_armoury.rog_tunables->min_power_cores;
>>> + max = asus_armoury.rog_tunables->max_power_cores;
>>> + }
>>> +
>>> + if (new_cores < min || new_cores > max)
>>> + return -EINVAL;
>>> +
>>> + out_val = 0;
>>> + out_val |= FIELD_PREP(ASUS_PERF_CORE_MASK, perf_cores);
>>> + out_val |= FIELD_PREP(ASUS_POWER_CORE_MASK, powr_cores);
>>> +
>>> + mutex_lock(&asus_armoury.mutex);
>>> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, out_val, &result);
>>> + mutex_unlock(&asus_armoury.mutex);
>>> +
>>> + if (err) {
>>> + pr_warn("Failed to set CPU core count: %d\n", err);
>>> + return err;
>>> + }
>>> +
>>> + if (result > 1) {
>>> + pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
>>> + return -EIO;
>>> + }
>>> +
>>> + pr_info("CPU core count changed, reboot required\n");
>>> + sysfs_notify(kobj, NULL, attr->attr.name);
>>> + asus_set_reboot_and_signal_event();
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static ssize_t cores_performance_min_value_show(struct kobject *kobj,
>>> + struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
>>> +}
>>> +
>>> +static ssize_t cores_performance_max_value_show(struct kobject *kobj,
>>> + struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
>>> +}
>>> +
>>> +static ssize_t cores_performance_default_value_show(struct kobject *kobj,
>>> +     struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
>>> +}
>>> +
>>> +static ssize_t cores_performance_current_value_show(struct kobject *kobj,
>>> +     struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
>>> +}
>>> +
>>> +static ssize_t cores_performance_current_value_store(struct kobject *kobj,
>>> +      struct kobj_attribute *attr,
>>> +      const char *buf, size_t count)
>>> +{
>>> + int err;
>>> +
>>> + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
>>> + if (err)
>>> + return err;
>>> +
>>> + return count;
>>> +}
>>> +ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
>>> +     "Set the max available performance cores");
>>> +
>>> +static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +        char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
>>> +}
>>> +
>>> +static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>>> +        char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
>>> +}
>>> +
>>> +static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
>>> +    struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
>>> +}
>>> +
>>> +static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
>>> +    struct kobj_attribute *attr, char *buf)
>>> +{
>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
>>> +}
>>> +
>>> +static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
>>> +     struct kobj_attribute *attr, const char *buf,
>>> +     size_t count)
>>> +{
>>> + int err;
>>> +
>>> + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
>>> + if (err)
>>> + return err;
>>> +
>>> + return count;
>>> +}
>>> +ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
>>> +     "Set the max available efficiency cores");
>>> +
>>>    /* Simple attribute creation */
>>>    ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
>>>           cpu_min, cpu_max, 1, "Set the CPU slow package limit");
>>> @@ -625,6 +841,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>>>    { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
>>>    { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
>>>    { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
>>> + { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
>>> + { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
>>>    
>>>    { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
>>>    { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
>>> @@ -802,6 +1020,7 @@ static int __init asus_fw_init(void)
>>>    return -ENOMEM;
>>>    
>>>    init_rog_tunables(asus_armoury.rog_tunables);
>>> + init_max_cpu_cores();
>>>    
>>>    err = asus_fw_attr_add();
>>>    if (err)
>>> diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
>>> index a5f95e806b4b..f400e3af24be 100644
>>> --- a/drivers/platform/x86/asus-armoury.h
>>> +++ b/drivers/platform/x86/asus-armoury.h
>>> @@ -167,6 +167,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>>    .name = _fsname, .attrs = _attrname##_attrs               \
>>>    }
>>>    
>>> +/* CPU core attributes need a little different in setup */
>>> +#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname)              \
>>> + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1);        \
>>> + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
>>> + static struct kobj_attribute attr_##_attrname##_current_value = \
>>> + __ASUS_ATTR_RW(_attrname, current_value);               \
>>> + static struct kobj_attribute attr_##_attrname##_default_value = \
>>> + __ASUS_ATTR_RO(_attrname, default_value);               \
>>> + static struct kobj_attribute attr_##_attrname##_min_value =     \
>>> + __ASUS_ATTR_RO(_attrname, min_value);                   \
>>> + static struct kobj_attribute attr_##_attrname##_max_value =     \
>>> + __ASUS_ATTR_RO(_attrname, max_value);                   \
>>> + static struct kobj_attribute attr_##_attrname##_type =          \
>>> + __ASUS_ATTR_RO_AS(type, int_type_show);                 \
>>> + static struct attribute *_attrname##_attrs[] = {                \
>>> + &attr_##_attrname##_current_value.attr,                 \
>>> + &attr_##_attrname##_default_value.attr,                 \
>>> + &attr_##_attrname##_min_value.attr,                     \
>>> + &attr_##_attrname##_max_value.attr,                     \
>>> + &attr_##_attrname##_scalar_increment.attr,              \
>>> + &attr_##_attrname##_display_name.attr,                  \
>>> + &attr_##_attrname##_type.attr,                          \
>>> + NULL                                                    \
>>> + };                                                              \
>>> + static const struct attribute_group _attrname##_attr_group = {  \
>>> + .name = _fsname, .attrs = _attrname##_attrs             \
>>> + }
>>> +
>>>    /*
>>>     * ROG PPT attributes need a little different in setup as they
>>>     * require rog_tunables members.
>>> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
>>> index e1aeafdf05d5..8964e601543a 100644
>>> --- a/include/linux/platform_data/x86/asus-wmi.h
>>> +++ b/include/linux/platform_data/x86/asus-wmi.h
>>> @@ -134,6 +134,10 @@
>>>    /* dgpu on/off */
>>>    #define ASUS_WMI_DEVID_DGPU 0x00090020
>>>    
>>> +/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
>>> +#define ASUS_WMI_DEVID_CORES 0x001200D2
>>> + /* Maximum Intel E-core and P-core availability */
>>> +#define ASUS_WMI_DEVID_CORES_MAX 0x001200D3
>>>    #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
>>>    #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
>>>    #define ASUS_WMI_DEVID_APU_MEM 0x000600C1
>>
>>


^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
  2024-09-26 14:56   ` Mario Limonciello
@ 2024-09-26 22:04     ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-26 22:04 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary


On Fri, 27 Sep 2024, at 2:56 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > With the existence of the asus-bioscfg module the attributes no-longer
> > need to live under the /sys/devices/platform/asus-nb-wmi/ path.
> > 
> > Deprecate all those that were implemented in asus-bioscfg with the goal

Damn I thought I had changed this commit message. Neds to mention `asus-armoury`.

> > of removing them fully in the next LTS cycle.
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> 
> I have some very minor nits below.  With them fixed:
> 
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

Thank you.

> > ---
> >   .../ABI/testing/sysfs-platform-asus-wmi       |  17 +++
> >   drivers/platform/x86/Kconfig                  |   9 ++
> >   drivers/platform/x86/asus-wmi.c               | 134 ++++++++++++++----
> >   3 files changed, 130 insertions(+), 30 deletions(-)
> > 
> > diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > index 28144371a0f1..765d50b0d9df 100644
> > --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > @@ -63,6 +63,7 @@ Date: Aug 2022
> >   KernelVersion: 6.1
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Switch the GPU hardware MUX mode. Laptops with this feature can
> >   can be toggled to boot with only the dGPU (discrete mode) or in
> >   standard Optimus/Hybrid mode. On switch a reboot is required:
> > @@ -75,6 +76,7 @@ Date: Aug 2022
> >   KernelVersion: 5.17
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Disable discrete GPU:
> >   * 0 - Enable dGPU,
> >   * 1 - Disable dGPU
> > @@ -84,6 +86,7 @@ Date: Aug 2022
> >   KernelVersion: 5.17
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Enable the external GPU paired with ROG X-Flow laptops.
> >   Toggling this setting will also trigger ACPI to disable the dGPU:
> >   
> > @@ -95,6 +98,7 @@ Date: Aug 2022
> >   KernelVersion: 5.17
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Enable an LCD response-time boost to reduce or remove ghosting:
> >   * 0 - Disable,
> >   * 1 - Enable
> > @@ -104,6 +108,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Get the current charging mode being used:
> >   * 1 - Barrel connected charger,
> >   * 2 - USB-C charging
> > @@ -114,6 +119,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Show if the egpu (XG Mobile) is correctly connected:
> >   * 0 - False,
> >   * 1 - True
> > @@ -123,6 +129,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Change the mini-LED mode:
> >   * 0 - Single-zone,
> >   * 1 - Multi-zone
> > @@ -133,6 +140,7 @@ Date: Apr 2024
> >   KernelVersion: 6.10
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   List the available mini-led modes.
> >   
> >   What: /sys/devices/platform/<platform>/ppt_pl1_spl
> > @@ -140,6 +148,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
> >   Shown on Intel+Nvidia or AMD+Nvidia based systems:
> >   
> > @@ -150,6 +159,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
> >   on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems:
> >   
> > @@ -160,6 +170,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only:
> >   * min=5, max=250
> >   
> > @@ -168,6 +179,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the APU SPPT limit. Shown on full AMD systems only:
> >   * min=5, max=130
> >   
> > @@ -176,6 +188,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the platform SPPT limit. Shown on full AMD systems only:
> >   * min=5, max=130
> >   
> > @@ -184,6 +197,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the dynamic boost limit of the Nvidia dGPU:
> >   * min=5, max=25
> >   
> > @@ -192,6 +206,7 @@ Date: Jun 2023
> >   KernelVersion: 6.5
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set the target temperature limit of the Nvidia dGPU:
> >   * min=75, max=87
> >   
> > @@ -200,6 +215,7 @@ Date: Apr 2024
> >   KernelVersion: 6.10
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set if the BIOS POST sound is played on boot.
> >   * 0 - False,
> >   * 1 - True
> > @@ -209,6 +225,7 @@ Date: Apr 2024
> >   KernelVersion: 6.10
> >   Contact: "Luke Jones" <luke@ljones.dev>
> >   Description:
> > +        DEPRECATED, WILL BE REMOVED SOON
> >   Set if the MCU can go in to low-power mode on system sleep
> >   * 0 - False,
> >   * 1 - True
> > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> > index dedf66e0d099..baa36413f6ed 100644
> > --- a/drivers/platform/x86/Kconfig
> > +++ b/drivers/platform/x86/Kconfig
> > @@ -300,6 +300,15 @@ config ASUS_WMI
> >     To compile this driver as a module, choose M here: the module will
> >     be called asus-wmi.
> >   
> > +config ASUS_WMI_DEPRECATED_ATTRS
> > + bool "BIOS option support in WMI platform (DEPRECATED)"
> > + depends on ASUS_WMI
> > + default y
> > + help
> > +   Say Y to expose the configurable BIOS options through the asus-wmi
> > +   driver. This can be used with or without the new asus-armoury driver which
> 
> Don't use the word "new" in a description.
> 
> > +   hasthe same attributes, but more, and better features.
> 
> has the
> 
> > +
> >   config ASUS_NB_WMI
> >   tristate "Asus Notebook WMI Driver"
> >   depends on ASUS_WMI
> > diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> > index 0a5221d65130..f553c0b33da7 100644
> > --- a/drivers/platform/x86/asus-wmi.c
> > +++ b/drivers/platform/x86/asus-wmi.c
> > @@ -289,11 +289,12 @@ struct asus_wmi {
> >   u8 fan_boost_mode_mask;
> >   u8 fan_boost_mode;
> >   
> > +
> > + /* Tunables provided by ASUS for gaming laptops */
> > + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> 
> Typically I would avoid indending the #if and #else.

Ack, changed. Will add missing match comment on the endif too.

> 
> >   bool egpu_enable_available;
> >   bool dgpu_disable_available;
> >   u32 gpu_mux_dev;
> > -
> > - /* Tunables provided by ASUS for gaming laptops */
> >   u32 ppt_pl2_sppt;
> >   u32 ppt_pl1_spl;
> >   u32 ppt_apu_sppt;
> > @@ -301,6 +302,9 @@ struct asus_wmi {
> >   u32 ppt_fppt;
> >   u32 nv_dynamic_boost;
> >   u32 nv_temp_target;
> > + bool panel_overdrive_available;
> > + u32 mini_led_dev_id;
> > + #endif
> 
> Typically I would avoid indending the #if and #else.

Ack, same for other locations in source. And added missing match comments to all locations.

> >   
> >   u32 kbd_rgb_dev;
> >   bool kbd_rgb_state_available;
> > @@ -319,9 +323,6 @@ struct asus_wmi {
> >   // The RSOC controls the maximum charging percentage.
> >   bool battery_rsoc_available;
> >   
> > - bool panel_overdrive_available;
> > - u32 mini_led_dev_id;
> > -
> >   struct hotplug_slot hotplug_slot;
> >   struct mutex hotplug_lock;
> >   struct mutex wmi_lock;
> > @@ -335,6 +336,15 @@ struct asus_wmi {
> >   struct asus_wmi_driver *driver;
> >   };
> >   
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> > +static void asus_wmi_show_deprecated(void)
> > +{
> > + pr_notice_once("Accessing attributes through /sys/bus/platform/asus_wmi "
> > + "is deprecated and will be removed in a future release. Please "
> > + "switch over to /sys/class/firmware_attributes.\n");
> > +}
> > +#endif
> > +
> >   /* WMI ************************************************************************/
> >   
> >   static int asus_wmi_evaluate_method3(u32 method_id,
> > @@ -732,6 +742,7 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
> >   }
> >   
> >   /* Charging mode, 1=Barrel, 2=USB ******************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t charge_mode_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -742,12 +753,16 @@ static ssize_t charge_mode_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", value & 0xff);
> >   }
> >   
> >   static DEVICE_ATTR_RO(charge_mode);
> > +#endif
> >   
> >   /* dGPU ********************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t dgpu_disable_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -758,6 +773,8 @@ static ssize_t dgpu_disable_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -811,8 +828,10 @@ static ssize_t dgpu_disable_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(dgpu_disable);
> > +#endif
> >   
> >   /* eGPU ********************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t egpu_enable_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -823,6 +842,8 @@ static ssize_t egpu_enable_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -879,8 +900,10 @@ static ssize_t egpu_enable_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(egpu_enable);
> > +#endif
> >   
> >   /* Is eGPU connected? *********************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t egpu_connected_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -891,12 +914,16 @@ static ssize_t egpu_connected_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> >   static DEVICE_ATTR_RO(egpu_connected);
> > +#endif
> >   
> >   /* gpu mux switch *************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t gpu_mux_mode_show(struct device *dev,
> >   struct device_attribute *attr, char *buf)
> >   {
> > @@ -907,6 +934,8 @@ static ssize_t gpu_mux_mode_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -965,6 +994,7 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(gpu_mux_mode);
> > +#endif
> >   
> >   /* TUF Laptop Keyboard RGB Modes **********************************************/
> >   static ssize_t kbd_rgb_mode_store(struct device *dev,
> > @@ -1088,6 +1118,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
> >   };
> >   
> >   /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t ppt_pl2_sppt_store(struct device *dev,
> >       struct device_attribute *attr,
> >       const char *buf, size_t count)
> > @@ -1126,6 +1157,8 @@ static ssize_t ppt_pl2_sppt_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->ppt_pl2_sppt);
> >   }
> >   static DEVICE_ATTR_RW(ppt_pl2_sppt);
> > @@ -1168,6 +1201,8 @@ static ssize_t ppt_pl1_spl_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->ppt_pl1_spl);
> >   }
> >   static DEVICE_ATTR_RW(ppt_pl1_spl);
> > @@ -1211,6 +1246,8 @@ static ssize_t ppt_fppt_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->ppt_fppt);
> >   }
> >   static DEVICE_ATTR_RW(ppt_fppt);
> > @@ -1254,6 +1291,8 @@ static ssize_t ppt_apu_sppt_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->ppt_apu_sppt);
> >   }
> >   static DEVICE_ATTR_RW(ppt_apu_sppt);
> > @@ -1297,6 +1336,8 @@ static ssize_t ppt_platform_sppt_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->ppt_platform_sppt);
> >   }
> >   static DEVICE_ATTR_RW(ppt_platform_sppt);
> > @@ -1340,6 +1381,8 @@ static ssize_t nv_dynamic_boost_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->nv_dynamic_boost);
> >   }
> >   static DEVICE_ATTR_RW(nv_dynamic_boost);
> > @@ -1383,11 +1426,15 @@ static ssize_t nv_temp_target_show(struct device *dev,
> >   {
> >   struct asus_wmi *asus = dev_get_drvdata(dev);
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%u\n", asus->nv_temp_target);
> >   }
> >   static DEVICE_ATTR_RW(nv_temp_target);
> > +#endif
> >   
> >   /* Ally MCU Powersave ********************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t mcu_powersave_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -1398,6 +1445,8 @@ static ssize_t mcu_powersave_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -1433,6 +1482,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(mcu_powersave);
> > +#endif
> >   
> >   /* Battery ********************************************************************/
> >   
> > @@ -2306,6 +2356,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
> >   }
> >   
> >   /* Panel Overdrive ************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t panel_od_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -2316,6 +2367,8 @@ static ssize_t panel_od_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -2352,9 +2405,10 @@ static ssize_t panel_od_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(panel_od);
> > +#endif
> >   
> >   /* Bootup sound ***************************************************************/
> > -
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t boot_sound_show(struct device *dev,
> >        struct device_attribute *attr, char *buf)
> >   {
> > @@ -2365,6 +2419,8 @@ static ssize_t boot_sound_show(struct device *dev,
> >   if (result < 0)
> >   return result;
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", result);
> >   }
> >   
> > @@ -2400,8 +2456,10 @@ static ssize_t boot_sound_store(struct device *dev,
> >   return count;
> >   }
> >   static DEVICE_ATTR_RW(boot_sound);
> > +#endif
> >   
> >   /* Mini-LED mode **************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t mini_led_mode_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -2432,6 +2490,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
> >   }
> >   }
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "%d\n", value);
> >   }
> >   
> > @@ -2502,10 +2562,13 @@ static ssize_t available_mini_led_mode_show(struct device *dev,
> >   return sysfs_emit(buf, "0 1 2\n");
> >   }
> >   
> > + asus_wmi_show_deprecated();
> > +
> >   return sysfs_emit(buf, "0\n");
> >   }
> >   
> >   static DEVICE_ATTR_RO(available_mini_led_mode);
> > +#endif
> >   
> >   /* Quirks *********************************************************************/
> >   
> > @@ -3804,6 +3867,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
> >   return 0;
> >   }
> >   
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   static ssize_t throttle_thermal_policy_show(struct device *dev,
> >      struct device_attribute *attr, char *buf)
> >   {
> > @@ -3847,6 +3911,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
> >    * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
> >    */
> >   static DEVICE_ATTR_RW(throttle_thermal_policy);
> > +#endif
> >   
> >   /* Platform profile ***********************************************************/
> >   static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
> > @@ -4474,27 +4539,29 @@ static struct attribute *platform_attributes[] = {
> >   &dev_attr_camera.attr,
> >   &dev_attr_cardr.attr,
> >   &dev_attr_touchpad.attr,
> > - &dev_attr_charge_mode.attr,
> > - &dev_attr_egpu_enable.attr,
> > - &dev_attr_egpu_connected.attr,
> > - &dev_attr_dgpu_disable.attr,
> > - &dev_attr_gpu_mux_mode.attr,
> >   &dev_attr_lid_resume.attr,
> >   &dev_attr_als_enable.attr,
> >   &dev_attr_fan_boost_mode.attr,
> > - &dev_attr_throttle_thermal_policy.attr,
> > - &dev_attr_ppt_pl2_sppt.attr,
> > - &dev_attr_ppt_pl1_spl.attr,
> > - &dev_attr_ppt_fppt.attr,
> > - &dev_attr_ppt_apu_sppt.attr,
> > - &dev_attr_ppt_platform_sppt.attr,
> > - &dev_attr_nv_dynamic_boost.attr,
> > - &dev_attr_nv_temp_target.attr,
> > - &dev_attr_mcu_powersave.attr,
> > - &dev_attr_boot_sound.attr,
> > - &dev_attr_panel_od.attr,
> > - &dev_attr_mini_led_mode.attr,
> > - &dev_attr_available_mini_led_mode.attr,
> > + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> > + &dev_attr_charge_mode.attr,
> > + &dev_attr_egpu_enable.attr,
> > + &dev_attr_egpu_connected.attr,
> > + &dev_attr_dgpu_disable.attr,
> > + &dev_attr_gpu_mux_mode.attr,
> > + &dev_attr_ppt_pl2_sppt.attr,
> > + &dev_attr_ppt_pl1_spl.attr,
> > + &dev_attr_ppt_fppt.attr,
> > + &dev_attr_ppt_apu_sppt.attr,
> > + &dev_attr_ppt_platform_sppt.attr,
> > + &dev_attr_nv_dynamic_boost.attr,
> > + &dev_attr_nv_temp_target.attr,
> > + &dev_attr_mcu_powersave.attr,
> > + &dev_attr_boot_sound.attr,
> > + &dev_attr_panel_od.attr,
> > + &dev_attr_mini_led_mode.attr,
> > + &dev_attr_available_mini_led_mode.attr,
> > + &dev_attr_throttle_thermal_policy.attr,
> > + #endif
> >   NULL
> >   };
> >   
> > @@ -4516,7 +4583,11 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> >   devid = ASUS_WMI_DEVID_LID_RESUME;
> >   else if (attr == &dev_attr_als_enable.attr)
> >   devid = ASUS_WMI_DEVID_ALS_ENABLE;
> > - else if (attr == &dev_attr_charge_mode.attr)
> > + else if (attr == &dev_attr_fan_boost_mode.attr)
> > + ok = asus->fan_boost_mode_available;
> > +
> > + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> > + if (attr == &dev_attr_charge_mode.attr)
> >   devid = ASUS_WMI_DEVID_CHARGE_MODE;
> >   else if (attr == &dev_attr_egpu_enable.attr)
> >   ok = asus->egpu_enable_available;
> > @@ -4554,6 +4625,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> >   ok = asus->mini_led_dev_id != 0;
> >   else if (attr == &dev_attr_available_mini_led_mode.attr)
> >   ok = asus->mini_led_dev_id != 0;
> > + #endif
> >   
> >   if (devid != -1) {
> >   ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
> > @@ -4794,6 +4866,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> >   goto fail_platform;
> >   
> >   /* ensure defaults for tunables */
> > + #if IS_ENABLED(CONFIG_ASUS_WMI_DEPRECATED_ATTRS)
> >   asus->ppt_pl2_sppt = 5;
> >   asus->ppt_pl1_spl = 5;
> >   asus->ppt_apu_sppt = 5;
> > @@ -4818,16 +4891,17 @@ static int asus_wmi_add(struct platform_device *pdev)
> >   else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX_VIVO))
> >   asus->gpu_mux_dev = ASUS_WMI_DEVID_GPU_MUX_VIVO;
> >   
> > - if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
> > - asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
> > - else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
> > - asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
> > -
> > + #endif /* CONFIG_ASUS_WMI_DEPRECATED_ATTRS */
> >   if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
> >   asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
> >   else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
> >   asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
> >   
> > + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE))
> > + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE;
> > + else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
> > + asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
> > +
> >   err = fan_boost_mode_check_present(asus);
> >   if (err)
> >   goto fail_fan_boost_mode;
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute
  2024-09-26 15:17   ` Mario Limonciello
@ 2024-09-26 22:12     ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-26 22:12 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Fri, 27 Sep 2024, at 3:17 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > Add panel_hd_mode to toggle the panel mode between single and high
> > definition modes.
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> 
> This patch looks good to me.
> 
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

Thank you.

> ---
> 
> But that being said; mostly to satisfy my curiosity could you share more 
> about what this actually does?
> 
> Does it change the EDID exposed in the BIOS in ACPI _DDC?  At least for 
> AMD platforms that would mean it only works with this patch (which is on 
> it's way):
> 
> https://lore.kernel.org/amd-gfx/20240918213845.158293-11-mario.limonciello@amd.com/

I don't have access to the hardware so what it does is learned entirely thirdhand. What I do know is that it must be rebooted after and it seems to switch some internal thingy.

"UHD 120Hz and FHD 240Hz modes" is what I gather from reviewing some of Sergei's code in his ghelper project (windows armoury crate replacement).

> 
> > ---
> >   drivers/platform/x86/asus-armoury.c        | 6 +++++-
> >   include/linux/platform_data/x86/asus-wmi.h | 1 +
> >   2 files changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> > index 39e422b16b8e..15eab4d45b81 100644
> > --- a/drivers/platform/x86/asus-armoury.c
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -106,7 +106,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> >   
> >   static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
> >   {
> > - return !strcmp(attr->attr.name, "gpu_mux_mode");
> > + return !strcmp(attr->attr.name, "gpu_mux_mode") ||
> > +        !strcmp(attr->attr.name, "panel_hd_mode");
> >   }
> >   
> >   /**
> > @@ -429,6 +430,8 @@ ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
> >      "Set MCU powersaving mode");
> >   ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
> >      "Set the panel refresh overdrive");
> > +ATTR_GROUP_BOOL_RW(panel_hd_mode, "panel_hd_mode", ASUS_WMI_DEVID_PANEL_HD,
> > +    "Set the panel HD mode to UHD<0> or FHD<1>");
> >   ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
> >      "Show the eGPU connection status");
> >   
> > @@ -442,6 +445,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
> >   { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> >   { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
> >   { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
> > + { &panel_hd_mode_attr_group, ASUS_WMI_DEVID_PANEL_HD },
> >   };
> >   
> >   static int asus_fw_attr_add(void)
> > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> > index 6ea4dedfb85e..7caf2c7ed8c9 100644
> > --- a/include/linux/platform_data/x86/asus-wmi.h
> > +++ b/include/linux/platform_data/x86/asus-wmi.h
> > @@ -73,6 +73,7 @@
> >   #define ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO 0x00110019
> >   
> >   /* Misc */
> > +#define ASUS_WMI_DEVID_PANEL_HD 0x0005001C
> >   #define ASUS_WMI_DEVID_PANEL_OD 0x00050019
> >   #define ASUS_WMI_DEVID_CAMERA 0x00060013
> >   #define ASUS_WMI_DEVID_LID_FLIP 0x00060062
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support
  2024-09-26 15:25   ` Mario Limonciello
@ 2024-09-26 22:14     ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-26 22:14 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Fri, 27 Sep 2024, at 3:25 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > Implement the APU memory size control under the asus-armoury module using
> > the fw_attributes class.
> > 
> > This allows the APU allocated memory size to be adjusted depending on
> > the users priority. A reboot is required after change.
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> 
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>

Thank you :)

> > ---
> >   drivers/platform/x86/asus-armoury.c        | 114 +++++++++++++++++++++
> >   include/linux/platform_data/x86/asus-wmi.h |   1 +
> >   2 files changed, 115 insertions(+)
> > 
> > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> > index 0f67b5deb629..a0022dcee3a4 100644
> > --- a/drivers/platform/x86/asus-armoury.c
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -456,6 +456,119 @@ static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj
> >   WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
> >   ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
> >   
> > +/* Device memory available to APU */
> > +
> > +static ssize_t apu_mem_current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +   char *buf)
> > +{
> > + int err;
> > + u32 mem;
> > +
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_APU_MEM, &mem);
> > + if (err)
> > + return err;
> > +
> > + switch (mem) {
> > + case 0x100:
> > + mem = 0;
> > + break;
> > + case 0x102:
> > + mem = 1;
> > + break;
> > + case 0x103:
> > + mem = 2;
> > + break;
> > + case 0x104:
> > + mem = 3;
> > + break;
> > + case 0x105:
> > + mem = 4;
> > + break;
> > + case 0x106:
> > + /* This is out of order and looks wrong but is correct */
> > + mem = 8;
> > + break;
> > + case 0x107:
> > + mem = 5;
> > + break;
> > + case 0x108:
> > + mem = 6;
> > + break;
> > + case 0x109:
> > + mem = 7;
> > + break;
> > + default:
> > + mem = 4;
> > + break;
> > + }
> > +
> > + return sysfs_emit(buf, "%u\n", mem);
> > +}
> > +
> > +static ssize_t apu_mem_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> > +    const char *buf, size_t count)
> > +{
> > + int result, err;
> > + u32 requested, mem;
> > +
> > + result = kstrtou32(buf, 10, &requested);
> > + if (result)
> > + return result;
> > +
> > + switch (requested) {
> > + case 0:
> > + mem = 0x000;
> > + break;
> > + case 1:
> > + mem = 0x102;
> > + break;
> > + case 2:
> > + mem = 0x103;
> > + break;
> > + case 3:
> > + mem = 0x104;
> > + break;
> > + case 4:
> > + mem = 0x105;
> > + break;
> > + case 5:
> > + mem = 0x107;
> > + break;
> > + case 6:
> > + mem = 0x108;
> > + break;
> > + case 7:
> > + mem = 0x109;
> > + break;
> > + case 8:
> > + /* This is out of order and looks wrong but is correct */
> > + mem = 0x106;
> > + break;
> > + default:
> > + return -EIO;
> > + }
> > +
> > + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_APU_MEM, mem, &result);
> > + if (err) {
> > + pr_warn("Failed to set apu_mem: %d\n", err);
> > + return err;
> > + }
> > +
> > + pr_info("APU memory changed to %uGB, reboot required\n", requested);
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > +
> > + asus_set_reboot_and_signal_event();
> > +
> > + return count;
> > +}
> > +
> > +static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +     char *buf)
> > +{
> > + return sysfs_emit(buf, "0;1;2;3;4;5;6;7;8\n");
> > +}
> > +ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
> > +
> >   /* Simple attribute creation */
> >   ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
> >          cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> > @@ -511,6 +624,7 @@ static const struct asus_attr_group armoury_attr_groups[] = {
> >   { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
> >   { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
> >   { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
> > + { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
> >   
> >   { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
> >   { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> > index 86629e621c61..e1aeafdf05d5 100644
> > --- a/include/linux/platform_data/x86/asus-wmi.h
> > +++ b/include/linux/platform_data/x86/asus-wmi.h
> > @@ -136,6 +136,7 @@
> >   
> >   #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
> >   #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
> > +#define ASUS_WMI_DEVID_APU_MEM 0x000600C1
> >   
> >   /* gpu mux switch, 0 = dGPU, 1 = Optimus */
> >   #define ASUS_WMI_DEVID_GPU_MUX 0x00090016
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs
  2024-09-26 15:22   ` Mario Limonciello
@ 2024-09-26 22:39     ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-26 22:39 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Fri, 27 Sep 2024, at 3:22 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > Adds the ppt_* and nv_* tuning knobs that are available via WMI methods
> > and adds proper min/max levels plus defaults.
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> > ---
> >   drivers/platform/x86/asus-armoury.c | 130 ++++++++++++++++++++++++++++
> >   drivers/platform/x86/asus-armoury.h |  65 ++++++++++++++
> >   2 files changed, 195 insertions(+)
> > 
> > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> > index 15eab4d45b81..766f944d0233 100644
> > --- a/drivers/platform/x86/asus-armoury.c
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -52,12 +52,40 @@
> >   #define NVIDIA_TEMP_MIN 75
> >   #define NVIDIA_TEMP_MAX 87
> >   
> > +/* Tunables provided by ASUS for gaming laptops */
> > +struct rog_tunables {
> > + u32 cpu_default;
> > + u32 cpu_min;
> > + u32 cpu_max;
> > +
> > + u32 platform_default;
> > + u32 platform_min;
> > + u32 platform_max;
> > +
> > + u32 ppt_pl1_spl; // cpu
> > + u32 ppt_pl2_sppt; // cpu
> > + u32 ppt_apu_sppt; // plat
> > + u32 ppt_platform_sppt; // plat
> > + u32 ppt_fppt; // cpu
> > +
> > + u32 nv_boost_default;
> > + u32 nv_boost_min;
> > + u32 nv_boost_max;
> > + u32 nv_dynamic_boost;
> > +
> > + u32 nv_temp_default;
> > + u32 nv_temp_min;
> > + u32 nv_temp_max;
> > + u32 nv_temp_target;
> > +};
> > +
> >   static const struct class *fw_attr_class;
> >   
> >   struct asus_armoury_priv {
> >   struct device *fw_attr_dev;
> >   struct kset *fw_attr_kset;
> >   
> > + struct rog_tunables *rog_tunables;
> >   u32 mini_led_dev_id;
> >   u32 gpu_mux_dev_id;
> >   
> > @@ -421,6 +449,25 @@ WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
> >   ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
> >   
> >   /* Simple attribute creation */
> > +ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
> > +        cpu_min, cpu_max, 1, "Set the CPU slow package limit");
> > +ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, "ppt_pl2_sppt", ASUS_WMI_DEVID_PPT_PL2_SPPT, cpu_default,
> > +        cpu_min, cpu_max, 1, "Set the CPU fast package limit");
> > +ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, "ppt_apu_sppt", ASUS_WMI_DEVID_PPT_APU_SPPT,
> > +        platform_default, platform_min, platform_max, 1,
> > +        "Set the CPU slow package limit");
> > +ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, "ppt_platform_sppt", ASUS_WMI_DEVID_PPT_PLAT_SPPT,
> > +        platform_default, platform_min, platform_max, 1,
> > +        "Set the CPU slow package limit");
> > +ATTR_GROUP_ROG_TUNABLE(ppt_fppt, "ppt_fppt", ASUS_WMI_DEVID_PPT_FPPT, cpu_default, cpu_min,
> > +        cpu_max, 1, "Set the CPU slow package limit");
> > +ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, "nv_dynamic_boost", ASUS_WMI_DEVID_NV_DYN_BOOST,
> > +        nv_boost_default, nv_boost_min, nv_boost_max, 1,
> > +        "Set the Nvidia dynamic boost limit");
> > +ATTR_GROUP_ROG_TUNABLE(nv_temp_target, "nv_temp_target", ASUS_WMI_DEVID_NV_THERM_TARGET,
> > +        nv_temp_default, nv_boost_min, nv_temp_max, 1,
> > +        "Set the Nvidia max thermal limit");
> > +
> >   ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
> >          "Show the current mode of charging");
> >   
> > @@ -441,6 +488,14 @@ static const struct asus_attr_group armoury_attr_groups[] = {
> >   { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
> >   { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
> >   
> > + { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL },
> > + { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT },
> > + { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT },
> > + { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT },
> > + { &ppt_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT },
> > + { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST },
> > + { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET },
> > +
> >   { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
> >   { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> >   { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
> > @@ -532,12 +587,87 @@ static int asus_fw_attr_add(void)
> >   
> >   /* Init / exit ****************************************************************/
> >   
> > +/* Set up the min/max and defaults for ROG tunables */
> > +static void init_rog_tunables(struct rog_tunables *rog)
> > +{
> > + const char *product;
> > + u32 max_boost = NVIDIA_BOOST_MAX;
> > + u32 cpu_default = PPT_CPU_LIMIT_DEFAULT;
> > + u32 cpu_max = PPT_CPU_LIMIT_MAX;
> > + u32 platform_default = PPT_PLATFORM_DEFAULT;
> > + u32 platform_max = PPT_PLATFORM_MAX;
> 
> Reverse xmas tree here.

Facepalm. Thanks.

> > +
> > + /*
> > + * ASUS product_name contains everything required, e.g,
> > + * "ROG Flow X16 GV601VV_GV601VV_00185149B"
> > + */
> > + product = dmi_get_system_info(DMI_PRODUCT_NAME);

Regarding the below, I think the above will always return somthing. I've never seen a blank product name. Unless this somehow errors?

> 
> It's really too bad there isn't somewhere to programatically get the 
> correct upper bounds in their API.
> 
> I'm wondering if you want something "like" this:
> 
> if (!product)
> pr_notice("Unknown hardware found.  Setting safe limits, please report 
> to get limits corrected\n");

From actual experience I've seen that if I max *all* of these variables out there are no ill effects. It looked like the internal limits took precedence.

But yes I wish there was a way to get the limits out of acpi. ASUS is normally good with this sort of thing but here it seems a bit shortsighted.

I will add some logging at least for some parts so there is awareness.

> > +
> > + if (strstr(product, "GA402R")) {
> > + cpu_default = 125;
> > + } else if (strstr(product, "13QY")) {
> > + cpu_max = 250;
> > + } else if (strstr(product, "X13")) {
> > + cpu_max = 75;
> > + cpu_default = 50;
> > + } else if (strstr(product, "RC71") || strstr(product, "RC72")) {
> > + cpu_max = 50;
> > + cpu_default = 30;
> > + } else if (strstr(product, "G814") || strstr(product, "G614") ||
> > +    strstr(product, "G834") || strstr(product, "G634")) {
> > + cpu_max = 175;
> > + } else if (strstr(product, "GA402X") || strstr(product, "GA403") ||
> > +    strstr(product, "FA507N") || strstr(product, "FA507X") ||
> > +    strstr(product, "FA707N") || strstr(product, "FA707X")) {
> > + cpu_max = 90;
> > + }

Maybe:
 else {
	pr_notice("Using default CPU limits. Please report if these are not correct.\n");
	}
??

For the below GPU boost limit, I wouldn't bother with similar, as far as I can tell it's not possible to go *over* the internal limit.

> > +
> > + if (strstr(product, "GZ301ZE"))
> > + max_boost = 5;
> > + else if (strstr(product, "FX507ZC4"))
> > + max_boost = 15;
> > + else if (strstr(product, "GU605"))
> > + max_boost = 20;
> > +
> > + /* ensure defaults for tunables */
> > + rog->cpu_default = cpu_default;
> > + rog->cpu_min = PPT_CPU_LIMIT_MIN;
> > + rog->cpu_max = cpu_max;
> > +
> > + rog->platform_default = platform_default;
> > + rog->platform_max = PPT_PLATFORM_MIN;
> > + rog->platform_max = platform_max;
> > +
> > + rog->ppt_pl1_spl = cpu_default;
> > + rog->ppt_pl2_sppt = cpu_default;
> > + rog->ppt_apu_sppt = cpu_default;
> > +
> > + rog->ppt_platform_sppt = platform_default;
> > + rog->ppt_fppt = cpu_default;
> > +
> > + rog->nv_boost_default = NVIDIA_BOOST_MAX;
> > + rog->nv_boost_max = NVIDIA_BOOST_MIN;
> > + rog->nv_boost_max = max_boost;
> > + rog->nv_dynamic_boost = NVIDIA_BOOST_MIN;
> > +
> > + rog->nv_temp_default = NVIDIA_TEMP_MAX;
> > + rog->nv_temp_max = NVIDIA_TEMP_MIN;
> > + rog->nv_temp_max = NVIDIA_TEMP_MAX;
> > + rog->nv_temp_target = NVIDIA_TEMP_MIN;
> > +}
> > +
> >   static int __init asus_fw_init(void)
> >   {
> >   int err;
> >   
> >   fw_attrs.pending_reboot = false;
> >   
> > + asus_armoury.rog_tunables = kzalloc(sizeof(struct rog_tunables), GFP_KERNEL);
> > + if (!asus_armoury.rog_tunables)
> > + return -ENOMEM;
> > +
> > + init_rog_tunables(asus_armoury.rog_tunables);
> > +
> >   err = asus_fw_attr_add();
> >   if (err)
> >   return err;
> > diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> > index b99fd136abf1..9e63ea0d9d44 100644
> > --- a/drivers/platform/x86/asus-armoury.h
> > +++ b/drivers/platform/x86/asus-armoury.h
> > @@ -17,6 +17,12 @@ static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
> >         const char *buf, size_t count, u32 min, u32 max,
> >         u32 *store_value, u32 wmi_dev);
> >   
> > +static ssize_t int_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +      char *buf)
> > +{
> > + return sysfs_emit(buf, "integer\n");
> > +}
> > +
> >   static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> >         char *buf)
> >   {
> > @@ -143,4 +149,63 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> >   .name = _fsname, .attrs = _attrname##_attrs               \
> >   }
> >   
> > +/*
> > + * ROG PPT attributes need a little different in setup as they
> > + * require rog_tunables members.
> > + */
> > +
> > +#define __ROG_TUNABLE_RW(_attr, _min, _max, _wmi)                             \
> > + static ssize_t _attr##_current_value_store(                           \
> > + struct kobject *kobj, struct kobj_attribute *attr,            \
> > + const char *buf, size_t count)                                \
> > + {                                                                     \
> > + return attr_int_store(kobj, attr, buf, count,                 \
> > +       asus_armoury.rog_tunables->_min,        \
> > +       asus_armoury.rog_tunables->_max,        \
> > +       &asus_armoury.rog_tunables->_attr,      \
> > +       _wmi);                                  \
> > + }                                                                     \
> > + static ssize_t _attr##_current_value_show(                            \
> > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> > + {                                                                     \
> > + return sysfs_emit(buf, "%u\n",                                \
> > +   asus_armoury.rog_tunables->_attr);          \
> > + }                                                                     \
> > + static struct kobj_attribute attr_##_attr##_current_value =           \
> > + __ASUS_ATTR_RW(_attr, current_value)
> > +
> > +#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val)                            \
> > + static ssize_t _attrname##_##_prop##_show(                            \
> > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> > + {                                                                     \
> > + return sysfs_emit(buf, "%d\n",                                \
> > +   asus_armoury.rog_tunables->_val);           \
> > + }                                                                     \
> > + static struct kobj_attribute attr_##_attrname##_##_prop =             \
> > + __ASUS_ATTR_RO(_attrname, _prop)
> > +
> > +#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _default, _min, _max, \
> > +        _incstep, _dispname)                            \
> > + __ROG_TUNABLE_SHOW(default_value, _attrname, _default);                \
> > + __ROG_TUNABLE_RW(_attrname, _min, _max, _wmi);                         \
> > + __ROG_TUNABLE_SHOW(min_value, _attrname, _min);                        \
> > + __ROG_TUNABLE_SHOW(max_value, _attrname, _max);                        \
> > + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", _incstep);        \
> > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);           \
> > + static struct kobj_attribute attr_##_attrname##_type =                 \
> > + __ASUS_ATTR_RO_AS(type, int_type_show);                        \
> > + static struct attribute *_attrname##_attrs[] = {                       \
> > + &attr_##_attrname##_current_value.attr,                        \
> > + &attr_##_attrname##_default_value.attr,                        \
> > + &attr_##_attrname##_min_value.attr,                            \
> > + &attr_##_attrname##_max_value.attr,                            \
> > + &attr_##_attrname##_scalar_increment.attr,                     \
> > + &attr_##_attrname##_display_name.attr,                         \
> > + &attr_##_attrname##_type.attr,                                 \
> > + NULL                                                           \
> > + };                                                                     \
> > + static const struct attribute_group _attrname##_attr_group = {         \
> > + .name = _fsname, .attrs = _attrname##_attrs                    \
> > + }
> > +
> >   #endif /* _ASUS_BIOSCFG_H_ */
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26 15:48   ` Mario Limonciello
@ 2024-09-26 23:20     ` Luke Jones
  2024-09-27 14:45       ` Mario Limonciello
  0 siblings, 1 reply; 39+ messages in thread
From: Luke Jones @ 2024-09-26 23:20 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

Very sorry. Another resend. This was *meant* to be in plain text sent as html for some reason.

On Fri, 27 Sep 2024, at 3:48 AM, Mario Limonciello wrote:
> On 9/26/2024 04:29, Luke D. Jones wrote:
> > The fw_attributes_class provides a much cleaner interface to all of the
> > attributes introduced to asus-wmi. This patch moves all of these extra
> 
> No need to say "this patch".

Ack

> > attributes over to fw_attributes_class, and shifts the bulk of these
> > definitions to a new kernel module to reduce the clutter of asus-wmi
> > with the intention of deprecating the asus-wmi attributes in future.
> > 
> > The work applies only to WMI methods which don't have a clearly defined
> > place within the sysfs and as a result ended up lumped together in
> > /sys/devices/platform/asus-nb-wmi/ with no standard API.
> > 
> > Where possible the fw attrs now implement defaults, min, max, scalar,
> > choices, etc. As en example dgpu_disable becomes:
> > 
> > /sys/class/firmware-attributes/asus-armoury/attributes/dgpu_disable/
> > ├── current_value
> > ├── display_name
> > ├── possible_values
> > └── type
> > 
> > as do other attributes.
> > 
> > The ppt_* based attributes are removed in this initial patch as the
> > implementation is somewhat broken due to the WMI methods requiring a
> > set of limits on the values accepted (which is not provided by WMI).
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> > ---
> >   drivers/platform/x86/Kconfig        |  13 +
> >   drivers/platform/x86/Makefile       |   1 +
> >   drivers/platform/x86/asus-armoury.c | 563 ++++++++++++++++++++++++++++
> >   drivers/platform/x86/asus-armoury.h | 146 ++++++++
> >   4 files changed, 723 insertions(+)
> >   create mode 100644 drivers/platform/x86/asus-armoury.c
> >   create mode 100644 drivers/platform/x86/asus-armoury.h
> > 
> > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> > index 3875abba5a79..dedf66e0d099 100644
> > --- a/drivers/platform/x86/Kconfig
> > +++ b/drivers/platform/x86/Kconfig
> > @@ -265,6 +265,19 @@ config ASUS_WIRELESS
> >     If you choose to compile this driver as a module the module will be
> >     called asus-wireless.
> >   
> > +config ASUS_ARMOURY
> > + tristate "ASUS Armoury driver"
> > + depends on ACPI_WMI
> 
> I don't think you need to depend on ACPI_WMI directly because ASUS_WMI 
> also depends on it.

Ack

> > + depends on ASUS_WMI
> > + select FW_ATTR_CLASS
> > + help
> > +   Say Y here if you have a WMI aware Asus machine and would like to use the
> > +   firmware_attributes API to control various settings typically exposed in
> > +   the ASUS Armoury Crate application available on Windows.
> > +
> > +   To compile this driver as a module, choose M here: the module will
> > +   be called asus-armoury.
> > +
> >   config ASUS_WMI
> >   tristate "ASUS WMI Driver"
> >   depends on ACPI_WMI
> > diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
> > index e1b142947067..fe3e7e7dede8 100644
> > --- a/drivers/platform/x86/Makefile
> > +++ b/drivers/platform/x86/Makefile
> > @@ -32,6 +32,7 @@ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
> >   # ASUS
> >   obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
> >   obj-$(CONFIG_ASUS_WIRELESS) += asus-wireless.o
> > +obj-$(CONFIG_ASUS_ARMOURY) += asus-armoury.o
> >   obj-$(CONFIG_ASUS_WMI) += asus-wmi.o
> >   obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o
> >   obj-$(CONFIG_ASUS_TF103C_DOCK) += asus-tf103c-dock.o
> > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
> > new file mode 100644
> > index 000000000000..39e422b16b8e
> > --- /dev/null
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -0,0 +1,563 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Asus Armoury (WMI) attributes driver. This driver uses the fw_attributes
> > + * class to expose the various WMI functions that many gaming and some
> > + * non-gaming ASUS laptops have available.
> > + * These typically don't fit anywhere else in the sysfs such as under LED class,
> > + * hwmon or other, and are set in Windows using the ASUS Armoury Crate tool.
> > + *
> > + * Copyright(C) 2010 Intel Corporation.
> > + * Copyright(C) 2024-2024 Luke Jones <luke@ljones.dev>
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/device.h>
> > +#include <linux/dmi.h>
> > +#include <linux/errno.h>
> > +#include <linux/fs.h>
> > +#include <linux/kernel.h>
> > +#include <linux/kmod.h>
> > +#include <linux/kobject.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/platform_data/x86/asus-wmi.h>
> > +#include <linux/types.h>
> > +
> > +#include "asus-armoury.h"
> > +#include "firmware_attributes_class.h"
> > +#include "asus-wmi.h"
> > +
> > +#define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C"
> > +
> > +#define ASUS_MINI_LED_MODE_MASK 0x03
> > +/* Standard modes for devices with only on/off */
> > +#define ASUS_MINI_LED_OFF 0x00
> > +#define ASUS_MINI_LED_ON 0x01
> > +/* Like "on" but the effect is more vibrant or brighter */
> > +#define ASUS_MINI_LED_STRONG_MODE 0x02
> > +/* New modes for devices with 3 mini-led mode types */
> > +#define ASUS_MINI_LED_2024_WEAK 0x00
> > +#define ASUS_MINI_LED_2024_STRONG 0x01
> > +#define ASUS_MINI_LED_2024_OFF 0x02
> > +
> > +/* Default limits for tunables available on ASUS ROG laptops */
> > +#define PPT_CPU_LIMIT_MIN 5
> > +#define PPT_CPU_LIMIT_MAX 150
> > +#define PPT_CPU_LIMIT_DEFAULT 80
> > +#define PPT_PLATFORM_MIN 5
> > +#define PPT_PLATFORM_MAX 100
> > +#define PPT_PLATFORM_DEFAULT 80
> > +#define NVIDIA_BOOST_MIN 5
> > +#define NVIDIA_BOOST_MAX 25
> > +#define NVIDIA_TEMP_MIN 75
> > +#define NVIDIA_TEMP_MAX 87
> 
> Purely for alphabetical order purposes shouldn't NVIDIA_* come before PPT*?

I guess :)

> Also can you leave a comment where these default limits come from?

Ack

> > +
> > +static const struct class *fw_attr_class;
> > +
> > +struct asus_armoury_priv {
> > + struct device *fw_attr_dev;
> > + struct kset *fw_attr_kset;
> > +
> > + u32 mini_led_dev_id;
> > + u32 gpu_mux_dev_id;
> > +
> > + struct mutex mutex;
> > +};
> > +
> > +static struct asus_armoury_priv asus_armoury = { .mutex = __MUTEX_INITIALIZER(
> > + asus_armoury.mutex) };
> > +
> > +struct fw_attrs_group {
> > + bool pending_reboot;
> > +};
> > +
> > +static struct fw_attrs_group fw_attrs = {
> > + .pending_reboot = false,
> > +};
> > +
> > +struct asus_attr_group {
> > + const struct attribute_group *attr_group;
> > + u32 wmi_devid;
> > +};
> > +
> > +static bool asus_wmi_is_present(u32 dev_id)
> > +{
> > + u32 retval;
> > + int status;
> > +
> > + status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id, 0, &retval);
> > + pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
> > +
> > + return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
> 
> It seems like you're hiding the potential ACPI failures which could make 
> this a bit harder to debug in the future.  What do you think about doing 
> it like this:
> 
> u32 ret;
> 
> if (!asus_wmi_evaluate_method()) {
> pr_debug("acpi_wmi_evaluate_method failed\n");
> return false;
> }
> 
> return ret & ASUS_WMI_DSDTS_PRESENCE_BIT;
> 
> > +}
> > +
> > +static void asus_set_reboot_and_signal_event(void)
> > +{
> > + fw_attrs.pending_reboot = true;
> > + kobject_uevent(&asus_armoury.fw_attr_dev->kobj, KOBJ_CHANGE);
> > +}
> > +
> > +static ssize_t pending_reboot_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
> > +{
> > + return sysfs_emit(buf, "%d\n", fw_attrs.pending_reboot);
> > +}
> > +
> > +static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
> > +
> > +static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
> > +{
> > + return !strcmp(attr->attr.name, "gpu_mux_mode");
> > +}
> > +
> > +/**
> > + * attr_int_store() - Generic store function for use with most WMI functions.
> > + * @kobj: Pointer to the driver object.
> > + * @kobj_attribute: Pointer to the attribute calling this function.
> > + * @buf: The buffer to read from, this is parsed to `int` type.
> > + * @count:
> 
> Missing a description here.

Ack

> 
> > + * @min: Minimum accepted value. Below this returns -EINVAL.
> > + * @max: Maximum accepted value. Above this returns -EINVAL.
> > + * @store_value: Pointer to where the parsed value should be stored.
> > + * @wmi_dev: The WMI function ID to use.
> > + *
> > + * The WMI functions available on most ASUS laptops return a 1 as "success", and
> > + * a 0 as failed. However some functions can return n > 1 for additional errors.
> > + * attr_int_store() currently treats all values which are not 1 as errors, ignoring
> 
> IMO; Don't refer to function() in the description.

Ack

> 
> > + * the possible differences in WMI error returns.
> > + *
> > + * Returns: Either count, or an error.
> > + */
> > +static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf,
> > +       size_t count, u32 min, u32 max, u32 *store_value, u32 wmi_dev)
> > +{
> > + u32 result, value;
> > + int err;
> > +
> > + err = kstrtouint(buf, 10, &value);
> > + if (err)
> > + return err;
> > +
> > + if (value < min || value > max)
> > + return -EINVAL;
> > +
> > + err = asus_wmi_set_devstate(wmi_dev, value, &result);
> > + if (err) {
> > + pr_err("Failed to set %s: %d\n", attr->attr.name, err);
> > + return err;
> > + }
> > +
> > + if (result != 1) {
> > + pr_err("Failed to set %s (result): 0x%x\n", attr->attr.name, result);
> > + return -EIO;
> > + }
> > +
> > + if (store_value != NULL)
> > + *store_value = value;
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > +
> > + if (asus_bios_requires_reboot(attr))
> > + asus_set_reboot_and_signal_event();
> > +
> > + return count;
> > +}
> > +
> > +/* Mini-LED mode **************************************************************/
> > +static ssize_t mini_led_mode_current_value_show(struct kobject *kobj,
> > + struct kobj_attribute *attr, char *buf)
> > +{
> > + u32 value;
> > + int err;
> > +
> > + err = asus_wmi_get_devstate_dsts(asus_armoury.mini_led_dev_id, &value);
> > + if (err)
> > + return err;
> > +
> > + value &= ASUS_MINI_LED_MODE_MASK;
> > +
> > + /*
> > + * Remap the mode values to match previous generation mini-LED. The last gen
> > + * WMI 0 == off, while on this version WMI 2 == off (flipped).
> > + */
> > + if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
> > + switch (value) {
> > + case ASUS_MINI_LED_2024_WEAK:
> > + value = ASUS_MINI_LED_ON;
> > + break;
> > + case ASUS_MINI_LED_2024_STRONG:
> > + value = ASUS_MINI_LED_STRONG_MODE;
> > + break;
> > + case ASUS_MINI_LED_2024_OFF:
> > + value = ASUS_MINI_LED_OFF;
> > + break;
> > + }
> > + }
> > +
> > + return sysfs_emit(buf, "%u\n", value);
> > +}
> > +
> > +static ssize_t mini_led_mode_current_value_store(struct kobject *kobj,
> > + struct kobj_attribute *attr, const char *buf,
> > + size_t count)
> > +{
> > + int result, err;
> > + u32 mode;
> > +
> > + err = kstrtou32(buf, 10, &mode);
> > + if (err)
> > + return err;
> > +
> > + if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE &&
> > +     mode > ASUS_MINI_LED_ON)
> > + return -EINVAL;
> > + if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2 &&
> > +     mode > ASUS_MINI_LED_STRONG_MODE)
> > + return -EINVAL;
> > +
> > + /*
> > + * Remap the mode values so expected behaviour is the same as the last
> > + * generation of mini-LED with 0 == off, 1 == on.
> > + */
> > + if (asus_armoury.mini_led_dev_id == ASUS_WMI_DEVID_MINI_LED_MODE2) {
> > + switch (mode) {
> > + case ASUS_MINI_LED_OFF:
> > + mode = ASUS_MINI_LED_2024_OFF;
> > + break;
> > + case ASUS_MINI_LED_ON:
> > + mode = ASUS_MINI_LED_2024_WEAK;
> > + break;
> > + case ASUS_MINI_LED_STRONG_MODE:
> > + mode = ASUS_MINI_LED_2024_STRONG;
> > + break;
> > + }
> > + }
> > +
> > + err = asus_wmi_set_devstate(asus_armoury.mini_led_dev_id, mode, &result);
> > + if (err) {
> > + pr_warn("Failed to set mini-LED: %d\n", err);
> > + return err;
> > + }
> > +
> > + if (result != 1) {
> > + pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
> > + return -EIO;
> > + }
> > +
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > +
> > + return count;
> > +}
> > +
> > +static ssize_t mini_led_mode_possible_values_show(struct kobject *kobj,
> > +   struct kobj_attribute *attr, char *buf)
> > +{
> > + switch (asus_armoury.mini_led_dev_id) {
> > + case ASUS_WMI_DEVID_MINI_LED_MODE:
> > + return sysfs_emit(buf, "0;1\n");
> > + case ASUS_WMI_DEVID_MINI_LED_MODE2:
> > + return sysfs_emit(buf, "0;1;2\n");
> > + }
> > +
> > + return sysfs_emit(buf, "0\n");
> > +}
> > +
> > +ATTR_GROUP_ENUM_CUSTOM(mini_led_mode, "mini_led_mode", "Set the mini-LED backlight mode");
> > +
> > +static ssize_t gpu_mux_mode_current_value_store(struct kobject *kobj,
> > + struct kobj_attribute *attr, const char *buf,
> > + size_t count)
> > +{
> > + int result, err;
> > + u32 optimus;
> > +
> > + err = kstrtou32(buf, 10, &optimus);
> > + if (err)
> > + return err;
> > +
> > + if (optimus > 1)
> > + return -EINVAL;
> > +
> > + if (asus_wmi_is_present(ASUS_WMI_DEVID_DGPU)) {
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_DGPU, &result);
> > + if (err)
> > + return err;
> > + if (result && !optimus) {
> > + err = -ENODEV;
> > + pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %02X %02X %d\n",
> > + result, optimus, err);
> > + return err;
> > + }
> > + }
> > +
> > + if (asus_wmi_is_present(ASUS_WMI_DEVID_EGPU)) {
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU, &result);
> > + if (err)
> > + return err;
> > + if (result && !optimus) {
> > + err = -ENODEV;
> > + pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n",
> > + err);
> > + return err;
> > + }
> > + }
> > +
> > + err = asus_wmi_set_devstate(asus_armoury.gpu_mux_dev_id, optimus, &result);
> > + if (err) {
> > + pr_err("Failed to set GPU MUX mode: %d\n", err);
> > + return err;
> > + }
> > + /* !1 is considered a fail by ASUS */
> > + if (result != 1) {
> > + pr_warn("Failed to set GPU MUX mode (result): 0x%x\n", result);
> > + return -EIO;
> > + }
> > +
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > + asus_set_reboot_and_signal_event();
> > +
> > + return count;
> > +}
> > +WMI_SHOW_INT(gpu_mux_mode_current_value, "%d\n", asus_armoury.gpu_mux_dev_id);
> > +ATTR_GROUP_BOOL_CUSTOM(gpu_mux_mode, "gpu_mux_mode", "Set the GPU display MUX mode");
> > +
> > +/*
> > + * A user may be required to store the value twice, typical store first, then
> > + * rescan PCI bus to activate power, then store a second time to save correctly.
> > + * The reason for this is that an extra code path in the ACPI is enabled when
> > + * the device and bus are powered.
> > + */
> > +static ssize_t dgpu_disable_current_value_store(struct kobject *kobj,
> > + struct kobj_attribute *attr, const char *buf,
> > + size_t count)
> > +{
> > + int result, err;
> > + u32 disable;
> > +
> > + err = kstrtou32(buf, 10, &disable);
> > + if (err)
> > + return err;
> > +
> > + if (disable > 1)
> > + return -EINVAL;
> > +
> > + if (asus_armoury.gpu_mux_dev_id) {
> > + err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
> > + if (err)
> > + return err;
> > + if (!result && disable) {
> > + err = -ENODEV;
> > + pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
> > + return err;
> > + }
> > + }
> > +
> > + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
> > + if (err) {
> > + pr_warn("Failed to set dGPU disable: %d\n", err);
> > + return err;
> > + }
> > +
> > + if (result != 1) {
> > + pr_warn("Failed to set dGPU disable (result): 0x%x\n", result);
> > + return -EIO;
> > + }
> > +
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > +
> > + return count;
> > +}
> > +WMI_SHOW_INT(dgpu_disable_current_value, "%d\n", ASUS_WMI_DEVID_DGPU);
> > +ATTR_GROUP_BOOL_CUSTOM(dgpu_disable, "dgpu_disable", "Disable the dGPU");
> > +
> > +/* The ACPI call to enable the eGPU also disables the internal dGPU */
> > +static ssize_t egpu_enable_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
> > +        const char *buf, size_t count)
> > +{
> > + int result, err;
> > + u32 enable;
> > +
> > + err = kstrtou32(buf, 10, &enable);
> > + if (err)
> > + return err;
> > +
> > + if (enable > 1)
> > + return -EINVAL;
> > +
> > + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_EGPU_CONNECTED, &result);
> > + if (err) {
> > + pr_warn("Failed to get eGPU connection status: %d\n", err);
> > + return err;
> > + }
> > +
> > + if (asus_armoury.gpu_mux_dev_id) {
> > + err = asus_wmi_get_devstate_dsts(asus_armoury.gpu_mux_dev_id, &result);
> > + if (err) {
> > + pr_warn("Failed to get GPU MUX status: %d\n", result);
> > + return result;
> > + }
> > + if (!result && enable) {
> > + err = -ENODEV;
> > + pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
> > + return err;
> > + }
> > + }
> > +
> > + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
> > + if (err) {
> > + pr_warn("Failed to set eGPU state: %d\n", err);
> > + return err;
> > + }
> > +
> > + if (result != 1) {
> > + pr_warn("Failed to set eGPU state (retval): 0x%x\n", result);
> > + return -EIO;
> > + }
> > +
> > + sysfs_notify(kobj, NULL, attr->attr.name);
> > +
> > + return count;
> > +}
> > +WMI_SHOW_INT(egpu_enable_current_value, "%d\n", ASUS_WMI_DEVID_EGPU);
> > +ATTR_GROUP_BOOL_CUSTOM(egpu_enable, "egpu_enable", "Enable the eGPU (also disables dGPU)");
> > +
> > +/* Simple attribute creation */
> > +ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2",
> > +        "Show the current mode of charging");
> > +
> > +ATTR_GROUP_BOOL_RW(boot_sound, "boot_sound", ASUS_WMI_DEVID_BOOT_SOUND,
> > +    "Set the boot POST sound");
> > +ATTR_GROUP_BOOL_RW(mcu_powersave, "mcu_powersave", ASUS_WMI_DEVID_MCU_POWERSAVE,
> > +    "Set MCU powersaving mode");
> > +ATTR_GROUP_BOOL_RW(panel_od, "panel_overdrive", ASUS_WMI_DEVID_PANEL_OD,
> > +    "Set the panel refresh overdrive");
> > +ATTR_GROUP_BOOL_RO(egpu_connected, "egpu_connected", ASUS_WMI_DEVID_EGPU_CONNECTED,
> > +    "Show the eGPU connection status");
> > +
> > +/* If an attribute does not require any special case handling add it here */
> > +static const struct asus_attr_group armoury_attr_groups[] = {
> > + { &egpu_connected_attr_group, ASUS_WMI_DEVID_EGPU_CONNECTED },
> > + { &egpu_enable_attr_group, ASUS_WMI_DEVID_EGPU },
> > + { &dgpu_disable_attr_group, ASUS_WMI_DEVID_DGPU },
> > +
> > + { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
> > + { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
> > + { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE },
> > + { &panel_od_attr_group, ASUS_WMI_DEVID_PANEL_OD },
> > +};
> > +
> > +static int asus_fw_attr_add(void)
> > +{
> > + int err;
> > +
> > + err = fw_attributes_class_get(&fw_attr_class);
> > + if (err)
> > + goto fail_class_created;
> 
> Is that right?  If you fail to get the class shouldn't you just return 
> an error code?

Indeed. I think I misread what i was referring to when I was learning how to use this. Changed.

> 
> > +
> > + asus_armoury.fw_attr_dev =
> > + device_create(fw_attr_class, NULL, MKDEV(0, 0), NULL, "%s", DRIVER_NAME);
> > +
> > + if (IS_ERR(asus_armoury.fw_attr_dev)) {
> > + err = PTR_ERR(asus_armoury.fw_attr_dev);
> > + goto fail_class_created;
> > + }
> > +
> > + asus_armoury.fw_attr_kset =
> > + kset_create_and_add("attributes", NULL, &asus_armoury.fw_attr_dev->kobj);
> > + if (!asus_armoury.fw_attr_dev) {
> > + err = -ENOMEM;
> > + pr_debug("Failed to create and add attributes\n");
> > + goto err_destroy_classdev;
> > + }
> > +
> > + err = sysfs_create_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
> > + if (err) {
> > + pr_warn("Failed to create sysfs level attributes\n");
> > + goto fail_class_created;
> > + }
> > +
> > + err = 0;
> This seems unnecessary.

I think my logic was I wasn't sure if the following body would set it. So be safe? But then if the previous code succeeeds then this shouldn't be set anyway :)

Removed in both locations.

> 
> > + asus_armoury.mini_led_dev_id = 0;
> > + if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
> > + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
> > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> > + &mini_led_mode_attr_group);
> > + } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
> > + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
> > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> > + &mini_led_mode_attr_group);
> > + }
> > + if (err)
> > + pr_warn("Failed to create sysfs-group for mini_led\n");
> 
> Shouldn't you fail and clean up here?

Honestly not sure. It's only a failed WMI call, and the group doesn't get created for that fail, the others might be fine. I'll defer to your advice on that.

> > +
> > + err = 0;
> 
> Assuming you follow my above comment this is unnecessary.

Ack

> 
> > + asus_armoury.gpu_mux_dev_id = 0;
> > + if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX)) {
> > + asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX;
> > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> > + &gpu_mux_mode_attr_group);
> > + } else if (asus_wmi_is_present(ASUS_WMI_DEVID_GPU_MUX_VIVO)) {
> > + asus_armoury.gpu_mux_dev_id = ASUS_WMI_DEVID_GPU_MUX_VIVO;
> > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> > + &gpu_mux_mode_attr_group);
> > + }
> > + if (err)
> > + pr_warn("Failed to create sysfs-group for gpu_mux\n");
> 
> Shouldn't you fail and clean up here?

Same as comment above the above

> > +
> > + for (int i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) {
> > + if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid))
> > + continue;
> > +
> > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
> > + armoury_attr_groups[i].attr_group);
> > + if (err)
> > + pr_warn("Failed to create sysfs-group for %s\n",
> > + armoury_attr_groups[i].attr_group->name);
> 
> Shouldn't you fail and clean up here?
> 
> > + else
> > + pr_debug("Created sysfs-group for %s\n",
> > + armoury_attr_groups[i].attr_group->name);
> > + }
> > +
> > + return 0;
> > +
> > +err_destroy_classdev:
> > + device_destroy(fw_attr_class, MKDEV(0, 0));
> > +
> > +fail_class_created:
> > + fw_attributes_class_put();
> > + return err;
> > +}
> > +
> > +/* Init / exit ****************************************************************/
> > +
> > +static int __init asus_fw_init(void)
> > +{
> > + int err;
> > +
> > + fw_attrs.pending_reboot = false;
> 
> Isn't it already initialized to false?

Rust makes me cautious :D. Removed.

> 
> > +
> > + err = asus_fw_attr_add();
> > + if (err)
> > + return err;
> > +
> > + return 0;
> > +}
> > +
> > +static void __exit asus_fw_exit(void)
> > +{
> > + mutex_lock(&asus_armoury.mutex);
> 
> I think you should be using this mutex more.  For example what if an 
> attribute is being written while the module is unloaded?

Good point. I'll adjust code to suit. However if I do, this will trickle through the other patches I've added your review tag to. Will this be okay?

> 
> > +
> > + sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr);
> > + kset_unregister(asus_armoury.fw_attr_kset);
> > + device_destroy(fw_attr_class, MKDEV(0, 0));
> > + fw_attributes_class_put();
> > +
> > + mutex_unlock(&asus_armoury.mutex);
> > +}
> > +
> > +module_init(asus_fw_init);
> > +module_exit(asus_fw_exit);
> > +
> > +MODULE_IMPORT_NS(ASUS_WMI);
> > +MODULE_AUTHOR("Luke Jones <luke@ljones.dev>");
> > +MODULE_DESCRIPTION("ASUS BIOS Configuration Driver");
> > +MODULE_LICENSE("GPL");
> > +MODULE_ALIAS("wmi:" ASUS_NB_WMI_EVENT_GUID);
> > diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
> > new file mode 100644
> > index 000000000000..b99fd136abf1
> > --- /dev/null
> > +++ b/drivers/platform/x86/asus-armoury.h
> > @@ -0,0 +1,146 @@
> > +/* SPDX-License-Identifier: GPL-2.0
> > + *
> > + * Definitions for kernel modules using asus-armoury driver
> > + *
> > + *  Copyright (c) 2024 Luke Jones <luke@ljones.dev>
> > + */
> > +
> > +#ifndef _ASUS_BIOSCFG_H_
> > +#define _ASUS_BIOSCFG_H_
> > +
> > +#include <linux/types.h>
> > +#include <linux/platform_device.h>
> > +
> > +#define DRIVER_NAME "asus-armoury"
> > +
> > +static ssize_t attr_int_store(struct kobject *kobj, struct kobj_attribute *attr,
> > +       const char *buf, size_t count, u32 min, u32 max,
> > +       u32 *store_value, u32 wmi_dev);
> > +
> > +static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
> > +       char *buf)
> > +{
> > + return sysfs_emit(buf, "enumeration\n");
> > +}
> > +
> > +#define __ASUS_ATTR_RO(_func, _name)                                  \
> > + {                                                             \
> > + .attr = { .name = __stringify(_name), .mode = 0444 }, \
> > + .show = _func##_##_name##_show,                       \
> > + }
> > +
> > +#define __ASUS_ATTR_RO_AS(_name, _show)                               \
> > + {                                                             \
> > + .attr = { .name = __stringify(_name), .mode = 0444 }, \
> > + .show = _show,                                        \
> > + }
> > +
> > +#define __ASUS_ATTR_RW(_func, _name) \
> > + __ATTR(_name, 0644, _func##_##_name##_show, _func##_##_name##_store)
> > +
> > +#define __WMI_STORE_INT(_attr, _min, _max, _wmi)                          \
> > + static ssize_t _attr##_store(struct kobject *kobj,                \
> > +      struct kobj_attribute *attr,         \
> > +      const char *buf, size_t count)       \
> > + {                                                                 \
> > + return attr_int_store(kobj, attr, buf, count, _min, _max, \
> > +       NULL, _wmi);                        \
> > + }
> > +
> > +#define WMI_SHOW_INT(_attr, _fmt, _wmi)                                     \
> > + static ssize_t _attr##_show(struct kobject *kobj,                   \
> > +     struct kobj_attribute *attr, char *buf) \
> > + {                                                                   \
> > + u32 result;                                                 \
> > + int err;                                                    \
> > + err = asus_wmi_get_devstate_dsts(_wmi, &result);            \
> > + if (err)                                                    \
> > + return err;                                         \
> > + return sysfs_emit(buf, _fmt,                                \
> > +   result & ~ASUS_WMI_DSTS_PRESENCE_BIT);    \
> > + }
> > +
> > +/* Create functions and attributes for use in other macros or on their own */
> > +
> > +#define __ATTR_CURRENT_INT_RO(_attr, _wmi)                          \
> > + WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
> > + static struct kobj_attribute attr_##_attr##_current_value = \
> > + __ASUS_ATTR_RO(_attr, current_value)
> > +
> > +#define __ATTR_CURRENT_INT_RW(_attr, _minv, _maxv, _wmi)            \
> > + __WMI_STORE_INT(_attr##_current_value, _minv, _maxv, _wmi); \
> > + WMI_SHOW_INT(_attr##_current_value, "%d\n", _wmi);          \
> > + static struct kobj_attribute attr_##_attr##_current_value = \
> > + __ASUS_ATTR_RW(_attr, current_value)
> > +
> > +/* Shows a formatted static variable */
> > +#define __ATTR_SHOW_FMT(_prop, _attrname, _fmt, _val)                         \
> > + static ssize_t _attrname##_##_prop##_show(                            \
> > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \
> > + {                                                                     \
> > + return sysfs_emit(buf, _fmt, _val);                           \
> > + }                                                                     \
> > + static struct kobj_attribute attr_##_attrname##_##_prop =             \
> > + __ASUS_ATTR_RO(_attrname, _prop)
> > +
> > +/* Boolean style enumeration, base macro. Requires adding show/store */
> > +#define __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)     \
> > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
> > + __ATTR_SHOW_FMT(possible_values, _attrname, "%s\n", _possible); \
> > + static struct kobj_attribute attr_##_attrname##_type =          \
> > + __ASUS_ATTR_RO_AS(type, enum_type_show);                \
> > + static struct attribute *_attrname##_attrs[] = {                \
> > + &attr_##_attrname##_current_value.attr,                 \
> > + &attr_##_attrname##_display_name.attr,                  \
> > + &attr_##_attrname##_possible_values.attr,               \
> > + &attr_##_attrname##_type.attr,                          \
> > + NULL                                                    \
> > + };                                                              \
> > + static const struct attribute_group _attrname##_attr_group = {  \
> > + .name = _fsname, .attrs = _attrname##_attrs             \
> > + }
> > +
> > +#define ATTR_GROUP_BOOL_RO(_attrname, _fsname, _wmi, _dispname) \
> > + __ATTR_CURRENT_INT_RO(_attrname, _wmi);                 \
> > + __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> > +
> > +#define ATTR_GROUP_BOOL_RW(_attrname, _fsname, _wmi, _dispname) \
> > + __ATTR_CURRENT_INT_RW(_attrname, 0, 1, _wmi);           \
> > + __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> > +
> > +/*
> > + * Requires <name>_current_value_show(), <name>_current_value_show()
> > + */
> > +#define ATTR_GROUP_BOOL_CUSTOM(_attrname, _fsname, _dispname)           \
> > + static struct kobj_attribute attr_##_attrname##_current_value = \
> > + __ASUS_ATTR_RW(_attrname, current_value);               \
> > + __ATTR_GROUP_ENUM(_attrname, _fsname, "0;1", _dispname)
> > +
> > +#define ATTR_GROUP_ENUM_INT_RO(_attrname, _fsname, _wmi, _possible, _dispname) \
> > + __ATTR_CURRENT_INT_RO(_attrname, _wmi);                                \
> > + __ATTR_GROUP_ENUM(_attrname, _fsname, _possible, _dispname)
> > +
> > +/*
> > + * Requires <name>_current_value_show(), <name>_current_value_show()
> > + * and <name>_possible_values_show()
> > + */
> > +#define ATTR_GROUP_ENUM_CUSTOM(_attrname, _fsname, _dispname)             \
> > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);      \
> > + static struct kobj_attribute attr_##_attrname##_current_value =   \
> > + __ASUS_ATTR_RW(_attrname, current_value);                 \
> > + static struct kobj_attribute attr_##_attrname##_possible_values = \
> > + __ASUS_ATTR_RO(_attrname, possible_values);               \
> > + static struct kobj_attribute attr_##_attrname##_type =            \
> > + __ASUS_ATTR_RO_AS(type, enum_type_show);                  \
> > + static struct attribute *_attrname##_attrs[] = {                  \
> > + &attr_##_attrname##_current_value.attr,                   \
> > + &attr_##_attrname##_display_name.attr,                    \
> > + &attr_##_attrname##_possible_values.attr,                 \
> > + &attr_##_attrname##_type.attr,                            \
> > + NULL                                                      \
> > + };                                                                \
> > + static const struct attribute_group _attrname##_attr_group = {    \
> > + .name = _fsname, .attrs = _attrname##_attrs               \
> > + }
> > +
> > +#endif /* _ASUS_BIOSCFG_H_ */
> 
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26 21:50     ` Luke Jones
@ 2024-09-27  6:09       ` Markus Elfring
  2024-09-27  7:05         ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Markus Elfring @ 2024-09-27  6:09 UTC (permalink / raw)
  To: Luke Jones, platform-driver-x86, linux-input, Benjamin Tissoires,
	Corentin Chary, Hans de Goede, Ilpo Järvinen, Jiri Kosina,
	Mario Limonciello
  Cc: LKML, kernel-janitors

>> …
>>> +++ b/drivers/platform/x86/asus-armoury.h
>>> @@ -0,0 +1,146 @@
>> …
>>> +#ifndef _ASUS_BIOSCFG_H_
>>> +#define _ASUS_BIOSCFG_H_
>> …
>>
>> I suggest to omit leading underscores from such identifiers.
>> https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier
> the link is C standard, not kernel C right?

Advice is offered in such a direction.


> Pretty much everything I look at in the kernel seems to use the leading underscores.

How much would you like to care for standard compliance concerns
together with your software developments?

Regards,
Markus

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-27  6:09       ` [v4 " Markus Elfring
@ 2024-09-27  7:05         ` Luke Jones
  2024-09-27  7:24           ` Markus Elfring
  0 siblings, 1 reply; 39+ messages in thread
From: Luke Jones @ 2024-09-27  7:05 UTC (permalink / raw)
  To: Markus Elfring, platform-driver-x86, linux-input,
	Benjamin Tissoires, Corentin Chary, Hans de Goede,
	Ilpo Järvinen, Jiri Kosina, Mario Limonciello
  Cc: LKML, kernel-janitors

html a third time... I think I need to do something about that. Very very sorry.

On Fri, 27 Sep 2024, at 6:09 PM, Markus Elfring wrote:
> >> …
> >>> +++ b/drivers/platform/x86/asus-armoury.h
> >>> @@ -0,0 +1,146 @@
> >> …
> >>> +#ifndef _ASUS_BIOSCFG_H_
> >>> +#define _ASUS_BIOSCFG_H_
> >> …
> >>
> >> I suggest to omit leading underscores from such identifiers.
> >> https://wiki.sei.cmu.edu/confluence/display/c/DCL37-C.+Do+not+declare+or+define+a+reserved+identifier
> …
> > the link is C standard, not kernel C right?
> 
> Advice is offered in such a direction.
> 
> 
> > Pretty much everything I look at in the kernel seems to use the leading underscores.
> 
> How much would you like to care for standard compliance concerns
> together with your software developments?

I only ask about because it seems to deviate from everything else I've viewed. For example the older `asus-wmi.h` has:

#ifndef _ASUS_WMI_H_
#define _ASUS_WMI_H_

and every other header in the drivers/platform/x86 dir is similar. If what I'm supposed to is omit the leading `_` then sure I'll do it, it's not of any consequence to me. But the difference gave me pause is all :)

Kind regards,
Luke.

> Regards,
> Markus
> 

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-27  7:05         ` Luke Jones
@ 2024-09-27  7:24           ` Markus Elfring
  2024-09-27  7:43             ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Markus Elfring @ 2024-09-27  7:24 UTC (permalink / raw)
  To: Luke Jones, platform-driver-x86, linux-input, Benjamin Tissoires,
	Corentin Chary, Hans de Goede, Ilpo Järvinen, Jiri Kosina,
	Mario Limonciello
  Cc: LKML, kernel-janitors

>> How much would you like to care for standard compliance concerns
>> together with your software developments?
>
> I only ask about because it seems to deviate from everything else I've viewed. For example the older `asus-wmi.h` has:
>
> #ifndef _ASUS_WMI_H_
> #define _ASUS_WMI_H_

Such a naming approach is “popular”, isn't it?


> and every other header in the drivers/platform/x86 dir is similar. If what I'm supposed to is omit the leading `_` then sure I'll do it, it's not of any consequence to me.

I dare to propose possibilities to take safer identifier selections better into account.
I hope that we can benefit more from corresponding collateral evolution.

Regards,
Markus

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-27  7:24           ` Markus Elfring
@ 2024-09-27  7:43             ` Luke Jones
  2024-09-27  7:48               ` Julia Lawall
  0 siblings, 1 reply; 39+ messages in thread
From: Luke Jones @ 2024-09-27  7:43 UTC (permalink / raw)
  To: Markus Elfring, platform-driver-x86, linux-input,
	Benjamin Tissoires, Corentin Chary, Hans de Goede,
	Ilpo Järvinen, Jiri Kosina, Mario Limonciello
  Cc: LKML, kernel-janitors

On Fri, 27 Sep 2024, at 7:24 PM, Markus Elfring wrote:
>>> How much would you like to care for standard compliance concerns
>>> together with your software developments?
>>
>> I only ask about because it seems to deviate from everything else I've viewed. For example the older `asus-wmi.h` has:
>>
>> #ifndef _ASUS_WMI_H_
>> #define _ASUS_WMI_H_
>
> Such a naming approach is “popular”, isn't it?
>
>
>> and every other header in the drivers/platform/x86 dir is similar. If what I'm supposed to is omit the leading `_` then sure I'll do it, it's not of any consequence to me.
>
> I dare to propose possibilities to take safer identifier selections 
> better into account.
> I hope that we can benefit more from corresponding collateral evolution.

My sincerest apologies if I missed something in my tone when trying to convey might thoughts - for some things I am still learning in regards to C (I am mostly rust) and the difference was a curious thing to me.

The code is now updated to match your suggestion.

> Regards,
> Markus

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-27  7:43             ` Luke Jones
@ 2024-09-27  7:48               ` Julia Lawall
  0 siblings, 0 replies; 39+ messages in thread
From: Julia Lawall @ 2024-09-27  7:48 UTC (permalink / raw)
  To: Luke Jones
  Cc: Markus Elfring, platform-driver-x86, linux-input,
	Benjamin Tissoires, Corentin Chary, Hans de Goede,
	Ilpo Järvinen, Jiri Kosina, Mario Limonciello, LKML,
	kernel-janitors

[-- Attachment #1: Type: text/plain, Size: 1403 bytes --]



On Fri, 27 Sep 2024, Luke Jones wrote:

> On Fri, 27 Sep 2024, at 7:24 PM, Markus Elfring wrote:
> >>> How much would you like to care for standard compliance concerns
> >>> together with your software developments?
> >>
> >> I only ask about because it seems to deviate from everything else I've viewed. For example the older `asus-wmi.h` has:
> >>
> >> #ifndef _ASUS_WMI_H_
> >> #define _ASUS_WMI_H_
> >
> > Such a naming approach is “popular”, isn't it?
> >
> >
> >> and every other header in the drivers/platform/x86 dir is similar. If what I'm supposed to is omit the leading `_` then sure I'll do it, it's not of any consequence to me.
> >
> > I dare to propose possibilities to take safer identifier selections
> > better into account.
> > I hope that we can benefit more from corresponding collateral evolution.
>
> My sincerest apologies if I missed something in my tone when trying to convey might thoughts - for some things I am still learning in regards to C (I am mostly rust) and the difference was a curious thing to me.
>
> The code is now updated to match your suggestion.

Markus is not an authority on Linux kernel codeing style, rather a
collector of random suggestions about C code that he would like to impose
on the Linux kernel.  So if you consider that his suggestion is not
appropriate in a Linux kernel context, please disregard it.

julia

>
> > Regards,
> > Markus
>
>

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-26 23:20     ` Luke Jones
@ 2024-09-27 14:45       ` Mario Limonciello
  2024-09-28  9:52         ` Luke Jones
  0 siblings, 1 reply; 39+ messages in thread
From: Mario Limonciello @ 2024-09-27 14:45 UTC (permalink / raw)
  To: Luke Jones, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On 9/26/2024 18:20, Luke Jones wrote:

>>> + asus_armoury.mini_led_dev_id = 0;
>>> + if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
>>> + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
>>> + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
>>> + &mini_led_mode_attr_group);
>>> + } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
>>> + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
>>> + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
>>> + &mini_led_mode_attr_group);
>>> + }
>>> + if (err)
>>> + pr_warn("Failed to create sysfs-group for mini_led\n");
>>
>> Shouldn't you fail and clean up here?
> 
> Honestly not sure. It's only a failed WMI call, and the group doesn't get created for that fail, the others might be fine. I'll defer to your advice on that.

It comes down to whether failures are expected on some machines or not 
in practice.

If a machine will fail to create groups, then yeah you should allow 
skipping.  If it doesn't then I feel you have a much more logical 
cleanup and support strategy if you unwind on any failure.

Hans or Ilpo might have some thoughts here too.

>> I think you should be using this mutex more.  For example what if an
>> attribute is being written while the module is unloaded?
> 
> Good point. I'll adjust code to suit. However if I do, this will trickle through the other patches I've added your review tag to. Will this be okay?
> 
>>

If they change in a material way drop my tag and I can just re-review.

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
  2024-09-26  9:29 ` [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
  2024-09-26 14:56   ` Mario Limonciello
@ 2024-09-28  0:13   ` kernel test robot
  2024-09-28 21:02     ` Luke Jones
  1 sibling, 1 reply; 39+ messages in thread
From: kernel test robot @ 2024-09-28  0:13 UTC (permalink / raw)
  To: Luke D. Jones, linux-kernel
  Cc: oe-kbuild-all, linux-input, bentiss, jikos, platform-driver-x86,
	ilpo.jarvinen, hdegoede, corentin.chary, superm1, Luke D. Jones

Hi Luke,

kernel test robot noticed the following build warnings:

[auto build test WARNING on hid/for-next]
[also build test WARNING on linus/master next-20240927]
[cannot apply to v6.11]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Luke-D-Jones/platform-x86-asus-wmi-export-symbols-used-for-read-write-WMI/20240926-173528
base:   https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git for-next
patch link:    https://lore.kernel.org/r/20240926092952.1284435-10-luke%40ljones.dev
patch subject: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
config: i386-randconfig-061-20240928 (https://download.01.org/0day-ci/archive/20240928/202409280735.meXnoMkl-lkp@intel.com/config)
compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240928/202409280735.meXnoMkl-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202409280735.meXnoMkl-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/asus-wmi.c:154:35: warning: unused variable 'asus_ally_mcu_quirk' [-Wunused-const-variable]
     154 | static const struct dmi_system_id asus_ally_mcu_quirk[] = {
         |                                   ^~~~~~~~~~~~~~~~~~~
   1 warning generated.


vim +/asus_ally_mcu_quirk +154 drivers/platform/x86/asus-wmi.c

0f0ac158d28ff7 Luke D. Jones 2021-10-24  153  
d2dfed310aae07 Luke D. Jones 2024-08-06 @154  static const struct dmi_system_id asus_ally_mcu_quirk[] = {
d2dfed310aae07 Luke D. Jones 2024-08-06  155  	{
d2dfed310aae07 Luke D. Jones 2024-08-06  156  		.matches = {
d2dfed310aae07 Luke D. Jones 2024-08-06  157  			DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
d2dfed310aae07 Luke D. Jones 2024-08-06  158  		},
d2dfed310aae07 Luke D. Jones 2024-08-06  159  	},
d2dfed310aae07 Luke D. Jones 2024-08-06  160  	{
d2dfed310aae07 Luke D. Jones 2024-08-06  161  		.matches = {
d2dfed310aae07 Luke D. Jones 2024-08-06  162  			DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
d2dfed310aae07 Luke D. Jones 2024-08-06  163  		},
d2dfed310aae07 Luke D. Jones 2024-08-06  164  	},
d2dfed310aae07 Luke D. Jones 2024-08-06  165  	{ },
d2dfed310aae07 Luke D. Jones 2024-08-06  166  };
d2dfed310aae07 Luke D. Jones 2024-08-06  167  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module
  2024-09-27 14:45       ` Mario Limonciello
@ 2024-09-28  9:52         ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-28  9:52 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Sat, 28 Sep 2024, at 2:45 AM, Mario Limonciello wrote:
> On 9/26/2024 18:20, Luke Jones wrote:
>
>>>> + asus_armoury.mini_led_dev_id = 0;
>>>> + if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE)) {
>>>> + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
>>>> + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
>>>> + &mini_led_mode_attr_group);
>>>> + } else if (asus_wmi_is_present(ASUS_WMI_DEVID_MINI_LED_MODE2)) {
>>>> + asus_armoury.mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE2;
>>>> + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj,
>>>> + &mini_led_mode_attr_group);
>>>> + }
>>>> + if (err)
>>>> + pr_warn("Failed to create sysfs-group for mini_led\n");
>>>
>>> Shouldn't you fail and clean up here?
>> 
>> Honestly not sure. It's only a failed WMI call, and the group doesn't get created for that fail, the others might be fine. I'll defer to your advice on that.
>
> It comes down to whether failures are expected on some machines or not 
> in practice.
>
> If a machine will fail to create groups, then yeah you should allow 
> skipping.  If it doesn't then I feel you have a much more logical 
> cleanup and support strategy if you unwind on any failure.
>
> Hans or Ilpo might have some thoughts here too.

I see now that I wasn't thinking clearly about this. I was zooming in on the asus_wmi_is_present() and just somehow blinding myself to the fact that, *that* isn't the error source.

Thank you for catching, I will update the code with proper unwind and handling. 

>>> I think you should be using this mutex more.  For example what if an
>>> attribute is being written while the module is unloaded?
>> 
>> Good point. I'll adjust code to suit. However if I do, this will trickle through the other patches I've added your review tag to. Will this be okay?
>> 
>>>
>
> If they change in a material way drop my tag and I can just re-review.

Looks like they haven't :)

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features
  2024-09-28  0:13   ` kernel test robot
@ 2024-09-28 21:02     ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-28 21:02 UTC (permalink / raw)
  To: kernel test robot, linux-kernel
  Cc: oe-kbuild-all, linux-input, Benjamin Tissoires, Jiri Kosina,
	platform-driver-x86, Ilpo Järvinen, Hans de Goede,
	corentin.chary, Mario Limonciello



On Sat, 28 Sep 2024, at 12:13 PM, kernel test robot wrote:
> Hi Luke,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on hid/for-next]
> [also build test WARNING on linus/master next-20240927]
> [cannot apply to v6.11]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url:    
> https://github.com/intel-lab-lkp/linux/commits/Luke-D-Jones/platform-x86-asus-wmi-export-symbols-used-for-read-write-WMI/20240926-173528
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/hid/hid.git 
> for-next
> patch link:    
> https://lore.kernel.org/r/20240926092952.1284435-10-luke%40ljones.dev
> patch subject: [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios 
> features
> config: i386-randconfig-061-20240928 
> (https://download.01.org/0day-ci/archive/20240928/202409280735.meXnoMkl-lkp@intel.com/config)
> compiler: clang version 18.1.8 (https://github.com/llvm/llvm-project 
> 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff)
> reproduce (this is a W=1 build): 
> (https://download.01.org/0day-ci/archive/20240928/202409280735.meXnoMkl-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new 
> version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: 
> https://lore.kernel.org/oe-kbuild-all/202409280735.meXnoMkl-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
>>> drivers/platform/x86/asus-wmi.c:154:35: warning: unused variable 'asus_ally_mcu_quirk' [-Wunused-const-variable]
>      154 | static const struct dmi_system_id asus_ally_mcu_quirk[] = {
>          |                                   ^~~~~~~~~~~~~~~~~~~
>    1 warning generated.


Not sure where this is coming from but it can be cleaned up by https://lore.kernel.org/platform-driver-x86/c19f3530-a065-461f-a5bf-ccc3988cf24c@amd.com/T/#t v2

>
> vim +/asus_ally_mcu_quirk +154 drivers/platform/x86/asus-wmi.c
>
> 0f0ac158d28ff7 Luke D. Jones 2021-10-24  153  
> d2dfed310aae07 Luke D. Jones 2024-08-06 @154  static const struct 
> dmi_system_id asus_ally_mcu_quirk[] = {
> d2dfed310aae07 Luke D. Jones 2024-08-06  155  	{
> d2dfed310aae07 Luke D. Jones 2024-08-06  156  		.matches = {
> d2dfed310aae07 Luke D. Jones 2024-08-06  157  
> 			DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> d2dfed310aae07 Luke D. Jones 2024-08-06  158  		},
> d2dfed310aae07 Luke D. Jones 2024-08-06  159  	},
> d2dfed310aae07 Luke D. Jones 2024-08-06  160  	{
> d2dfed310aae07 Luke D. Jones 2024-08-06  161  		.matches = {
> d2dfed310aae07 Luke D. Jones 2024-08-06  162  
> 			DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> d2dfed310aae07 Luke D. Jones 2024-08-06  163  		},
> d2dfed310aae07 Luke D. Jones 2024-08-06  164  	},
> d2dfed310aae07 Luke D. Jones 2024-08-06  165  	{ },
> d2dfed310aae07 Luke D. Jones 2024-08-06  166  };
> d2dfed310aae07 Luke D. Jones 2024-08-06  167  
>
> -- 
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 39+ messages in thread

* Re: [PATCH v4 8/9] platform/x86: asus-armoury: add core count control
  2024-09-26 22:02       ` Mario Limonciello
@ 2024-09-29  7:00         ` Luke Jones
  0 siblings, 0 replies; 39+ messages in thread
From: Luke Jones @ 2024-09-29  7:00 UTC (permalink / raw)
  To: Mario Limonciello, linux-kernel
  Cc: linux-input, Benjamin Tissoires, Jiri Kosina, platform-driver-x86,
	Ilpo Järvinen, Hans de Goede, corentin.chary

On Fri, 27 Sep 2024, at 10:02 AM, Mario Limonciello wrote:
> On 9/26/2024 16:47, Luke Jones wrote:
>> Resend, sorry. My email client defaults to HTML
>> 
>> On Fri, 27 Sep 2024, at 3:30 AM, Mario Limonciello wrote:
>>> On 9/26/2024 04:29, Luke D. Jones wrote:
>>>> Implement Intel core enablement under the asus-armoury module using the
>>>> fw_attributes class.
>>>>
>>>> This allows users to enable or disable preformance or efficiency cores
>>>> depending on their requirements. After change a reboot is required.
>>>>
>>>> Signed-off-by: Luke D. Jones <luke@ljones.dev>
>>>> ---
>>>>    drivers/platform/x86/asus-armoury.c        | 219 +++++++++++++++++++++
>>>>    drivers/platform/x86/asus-armoury.h        |  28 +++
>>>>    include/linux/platform_data/x86/asus-wmi.h |   4 +
>>>>    3 files changed, 251 insertions(+)
>>>>
>>>> diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c
>>>> index a0022dcee3a4..ce1facb40bd5 100644
>>>> --- a/drivers/platform/x86/asus-armoury.c
>>>> +++ b/drivers/platform/x86/asus-armoury.c
>>>> @@ -40,6 +40,21 @@
>>>>    #define ASUS_MINI_LED_2024_STRONG 0x01
>>>>    #define ASUS_MINI_LED_2024_OFF 0x02
>>>>    
>>>> +#define ASUS_POWER_CORE_MASK GENMASK(15, 8)
>>>> +#define ASUS_PERF_CORE_MASK GENMASK(7, 0)
>>>> +
>>>> +enum cpu_core_type {
>>>> + CPU_CORE_PERF = 0,
>>>> + CPU_CORE_POWER,
>>>> +};
>>>> +
>>>> +enum cpu_core_value {
>>>> + CPU_CORE_DEFAULT = 0,
>>>> + CPU_CORE_MIN,
>>>> + CPU_CORE_MAX,
>>>> + CPU_CORE_CURRENT,
>>>> +};
>>>> +
>>>>    /* Default limits for tunables available on ASUS ROG laptops */
>>>>    #define PPT_CPU_LIMIT_MIN 5
>>>>    #define PPT_CPU_LIMIT_MAX 150
>>>> @@ -85,6 +100,13 @@ struct rog_tunables {
>>>>    u32 dgpu_tgp_min;
>>>>    u32 dgpu_tgp_max;
>>>>    u32 dgpu_tgp;
>>>> +
>>>> + u32 cur_perf_cores;
>>>> + u32 min_perf_cores;
>>>> + u32 max_perf_cores;
>>>> + u32 cur_power_cores;
>>>> + u32 min_power_cores;
>>>> + u32 max_power_cores;
>>>>    };
>>>>    
>>>>    static const struct class *fw_attr_class;
>>>> @@ -143,6 +165,8 @@ static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);
>>>>    static bool asus_bios_requires_reboot(struct kobj_attribute *attr)
>>>>    {
>>>>    return !strcmp(attr->attr.name, "gpu_mux_mode") ||
>>>> +        !strcmp(attr->attr.name, "cores_performance") ||
>>>> +        !strcmp(attr->attr.name, "cores_efficiency") ||
>>>>           !strcmp(attr->attr.name, "panel_hd_mode");
>>>>    }
>>>>    
>>>> @@ -569,6 +593,198 @@ static ssize_t apu_mem_possible_values_show(struct kobject *kobj, struct kobj_at
>>>>    }
>>>>    ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set available system RAM (in GB) for the APU to use");
>>>>    
>>>> +static int init_max_cpu_cores(void)
>>>> +{
>>>> + u32 cores;
>>>> + int err;
>>>> +
>>>> + asus_armoury.rog_tunables->min_perf_cores = 4;
>>>> + asus_armoury.rog_tunables->max_perf_cores = 4;
>>>> + asus_armoury.rog_tunables->cur_perf_cores = 4;
>>>> + asus_armoury.rog_tunables->min_power_cores = 0;
>>>> + asus_armoury.rog_tunables->max_power_cores = 8;
>>>> + asus_armoury.rog_tunables->cur_power_cores = 8;
>>>
>>> This seems like it's going to be dependent upon "specific" CPU SKU, no?
>> 
>> It is yeah. I was trying to set some sort of default but forgot about it after the fact.
>> 
>>> If you can't detect the bounds from the WMI API I think it would be
>>> smarter to use the CPU vendor specific CPUID/MSR APIs to discover the
>>> topology and how many cores of the different types exist.
>> 
>> Thinking about it now I would rather set it as an error and disable the ability to set cores. What do you think?
>
> Seems fine to me.  Just make sure you mention it's intended behavior in 
> a comment somewhere if it's not obvious.

I've decided against my initial thoughts and added error return plus module fail out if that errors.

>> 
>>> Furthermore what about LP cores?  I guess those can't be turned and off
>>> from this API?
>> 
>> power/efficiency cores? They can be.
>
> Intel has 3 core types on some products.  "Performance", "efficiency" 
> and "low power".
>
> I don't know a lot about them, I just want to make sure you do so you 
> don't back yourself into a corner on API design.

Yeah I think it should be fairly independent of efficiency/power - kind of classing them as similar/same.

>> 
>>>> +
>>>> + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES_MAX, &cores);
>>>> + if (err)
>>>> + return err;
>>>> +
>>>> + cores &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
>>>> + asus_armoury.rog_tunables->max_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
>>>> + asus_armoury.rog_tunables->max_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
>>>> +
>>>> + cores = 0;
>>>> + err = asus_wmi_get_devstate_dsts(ASUS_WMI_DEVID_CORES, &cores);
>>>> + if (err)
>>>> + return err;
>>>> +
>>>> + asus_armoury.rog_tunables->cur_perf_cores = FIELD_GET(ASUS_PERF_CORE_MASK, cores);
>>>> + asus_armoury.rog_tunables->cur_power_cores = FIELD_GET(ASUS_POWER_CORE_MASK, cores);
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static ssize_t cores_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf,
>>>> + enum cpu_core_type core_type, enum cpu_core_value core_value)
>>>> +{
>>>> + u32 cores;
>>>> +
>>>> + switch (core_value) {
>>>> + case CPU_CORE_DEFAULT:
>>>> + case CPU_CORE_MAX:
>>>> + if (core_type == CPU_CORE_PERF)
>>>> + return sysfs_emit(buf, "%d\n",
>>>> +   asus_armoury.rog_tunables->max_perf_cores);
>>>> + else
>>>> + return sysfs_emit(buf, "%d\n",
>>>> +   asus_armoury.rog_tunables->max_power_cores);
>>>> + case CPU_CORE_MIN:
>>>> + if (core_type == CPU_CORE_PERF)
>>>> + return sysfs_emit(buf, "%d\n",
>>>> +   asus_armoury.rog_tunables->min_perf_cores);
>>>> + else
>>>> + return sysfs_emit(buf, "%d\n",
>>>> +   asus_armoury.rog_tunables->min_power_cores);
>>>> + default:
>>>> + break;
>>>> + }
>>>> +
>>>> + if (core_type == CPU_CORE_PERF)
>>>> + cores = asus_armoury.rog_tunables->cur_perf_cores;
>>>> + else
>>>> + cores = asus_armoury.rog_tunables->cur_power_cores;
>>>> +
>>>> + return sysfs_emit(buf, "%d\n", cores);
>>>> +}
>>>> +
>>>> +static ssize_t cores_current_value_store(struct kobject *kobj, struct kobj_attribute *attr,
>>>> + const char *buf, enum cpu_core_type core_type)
>>>> +{
>>>> + int result, err;
>>>> + u32 new_cores, perf_cores, powr_cores, out_val, min, max;
>>>> +
>>>> + result = kstrtou32(buf, 10, &new_cores);
>>>> + if (result)
>>>> + return result;
>>>> +
>>>> + if (core_type == CPU_CORE_PERF) {
>>>> + perf_cores = new_cores;
>>>> + powr_cores = out_val = asus_armoury.rog_tunables->cur_power_cores;
>>>> + min = asus_armoury.rog_tunables->min_perf_cores;
>>>> + max = asus_armoury.rog_tunables->max_perf_cores;
>>>> + } else {
>>>> + perf_cores = asus_armoury.rog_tunables->cur_perf_cores;
>>>> + powr_cores = out_val = new_cores;
>>>> + min = asus_armoury.rog_tunables->min_power_cores;
>>>> + max = asus_armoury.rog_tunables->max_power_cores;
>>>> + }
>>>> +
>>>> + if (new_cores < min || new_cores > max)
>>>> + return -EINVAL;
>>>> +
>>>> + out_val = 0;
>>>> + out_val |= FIELD_PREP(ASUS_PERF_CORE_MASK, perf_cores);
>>>> + out_val |= FIELD_PREP(ASUS_POWER_CORE_MASK, powr_cores);
>>>> +
>>>> + mutex_lock(&asus_armoury.mutex);
>>>> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES, out_val, &result);
>>>> + mutex_unlock(&asus_armoury.mutex);
>>>> +
>>>> + if (err) {
>>>> + pr_warn("Failed to set CPU core count: %d\n", err);
>>>> + return err;
>>>> + }
>>>> +
>>>> + if (result > 1) {
>>>> + pr_warn("Failed to set CPU core count (result): 0x%x\n", result);
>>>> + return -EIO;
>>>> + }
>>>> +
>>>> + pr_info("CPU core count changed, reboot required\n");
>>>> + sysfs_notify(kobj, NULL, attr->attr.name);
>>>> + asus_set_reboot_and_signal_event();
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static ssize_t cores_performance_min_value_show(struct kobject *kobj,
>>>> + struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MIN);
>>>> +}
>>>> +
>>>> +static ssize_t cores_performance_max_value_show(struct kobject *kobj,
>>>> + struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_MAX);
>>>> +}
>>>> +
>>>> +static ssize_t cores_performance_default_value_show(struct kobject *kobj,
>>>> +     struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_DEFAULT);
>>>> +}
>>>> +
>>>> +static ssize_t cores_performance_current_value_show(struct kobject *kobj,
>>>> +     struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_PERF, CPU_CORE_CURRENT);
>>>> +}
>>>> +
>>>> +static ssize_t cores_performance_current_value_store(struct kobject *kobj,
>>>> +      struct kobj_attribute *attr,
>>>> +      const char *buf, size_t count)
>>>> +{
>>>> + int err;
>>>> +
>>>> + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_PERF);
>>>> + if (err)
>>>> + return err;
>>>> +
>>>> + return count;
>>>> +}
>>>> +ATTR_GROUP_CORES_RW(cores_performance, "cores_performance",
>>>> +     "Set the max available performance cores");
>>>> +
>>>> +static ssize_t cores_efficiency_min_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>>>> +        char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MIN);
>>>> +}
>>>> +
>>>> +static ssize_t cores_efficiency_max_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>>>> +        char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_MAX);
>>>> +}
>>>> +
>>>> +static ssize_t cores_efficiency_default_value_show(struct kobject *kobj,
>>>> +    struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_DEFAULT);
>>>> +}
>>>> +
>>>> +static ssize_t cores_efficiency_current_value_show(struct kobject *kobj,
>>>> +    struct kobj_attribute *attr, char *buf)
>>>> +{
>>>> + return cores_value_show(kobj, attr, buf, CPU_CORE_POWER, CPU_CORE_CURRENT);
>>>> +}
>>>> +
>>>> +static ssize_t cores_efficiency_current_value_store(struct kobject *kobj,
>>>> +     struct kobj_attribute *attr, const char *buf,
>>>> +     size_t count)
>>>> +{
>>>> + int err;
>>>> +
>>>> + err = cores_current_value_store(kobj, attr, buf, CPU_CORE_POWER);
>>>> + if (err)
>>>> + return err;
>>>> +
>>>> + return count;
>>>> +}
>>>> +ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency",
>>>> +     "Set the max available efficiency cores");
>>>> +
>>>>    /* Simple attribute creation */
>>>>    ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, "ppt_pl1_spl", ASUS_WMI_DEVID_PPT_PL1_SPL, cpu_default,
>>>>           cpu_min, cpu_max, 1, "Set the CPU slow package limit");
>>>> @@ -625,6 +841,8 @@ static const struct asus_attr_group armoury_attr_groups[] = {
>>>>    { &dgpu_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP },
>>>>    { &dgpu_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP },
>>>>    { &apu_mem_attr_group, ASUS_WMI_DEVID_APU_MEM },
>>>> + { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX },
>>>> + { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX },
>>>>    
>>>>    { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE },
>>>>    { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND },
>>>> @@ -802,6 +1020,7 @@ static int __init asus_fw_init(void)
>>>>    return -ENOMEM;
>>>>    
>>>>    init_rog_tunables(asus_armoury.rog_tunables);
>>>> + init_max_cpu_cores();
>>>>    
>>>>    err = asus_fw_attr_add();
>>>>    if (err)
>>>> diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
>>>> index a5f95e806b4b..f400e3af24be 100644
>>>> --- a/drivers/platform/x86/asus-armoury.h
>>>> +++ b/drivers/platform/x86/asus-armoury.h
>>>> @@ -167,6 +167,34 @@ static ssize_t enum_type_show(struct kobject *kobj, struct kobj_attribute *attr,
>>>>    .name = _fsname, .attrs = _attrname##_attrs               \
>>>>    }
>>>>    
>>>> +/* CPU core attributes need a little different in setup */
>>>> +#define ATTR_GROUP_CORES_RW(_attrname, _fsname, _dispname)              \
>>>> + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1);        \
>>>> + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname);    \
>>>> + static struct kobj_attribute attr_##_attrname##_current_value = \
>>>> + __ASUS_ATTR_RW(_attrname, current_value);               \
>>>> + static struct kobj_attribute attr_##_attrname##_default_value = \
>>>> + __ASUS_ATTR_RO(_attrname, default_value);               \
>>>> + static struct kobj_attribute attr_##_attrname##_min_value =     \
>>>> + __ASUS_ATTR_RO(_attrname, min_value);                   \
>>>> + static struct kobj_attribute attr_##_attrname##_max_value =     \
>>>> + __ASUS_ATTR_RO(_attrname, max_value);                   \
>>>> + static struct kobj_attribute attr_##_attrname##_type =          \
>>>> + __ASUS_ATTR_RO_AS(type, int_type_show);                 \
>>>> + static struct attribute *_attrname##_attrs[] = {                \
>>>> + &attr_##_attrname##_current_value.attr,                 \
>>>> + &attr_##_attrname##_default_value.attr,                 \
>>>> + &attr_##_attrname##_min_value.attr,                     \
>>>> + &attr_##_attrname##_max_value.attr,                     \
>>>> + &attr_##_attrname##_scalar_increment.attr,              \
>>>> + &attr_##_attrname##_display_name.attr,                  \
>>>> + &attr_##_attrname##_type.attr,                          \
>>>> + NULL                                                    \
>>>> + };                                                              \
>>>> + static const struct attribute_group _attrname##_attr_group = {  \
>>>> + .name = _fsname, .attrs = _attrname##_attrs             \
>>>> + }
>>>> +
>>>>    /*
>>>>     * ROG PPT attributes need a little different in setup as they
>>>>     * require rog_tunables members.
>>>> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
>>>> index e1aeafdf05d5..8964e601543a 100644
>>>> --- a/include/linux/platform_data/x86/asus-wmi.h
>>>> +++ b/include/linux/platform_data/x86/asus-wmi.h
>>>> @@ -134,6 +134,10 @@
>>>>    /* dgpu on/off */
>>>>    #define ASUS_WMI_DEVID_DGPU 0x00090020
>>>>    
>>>> +/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
>>>> +#define ASUS_WMI_DEVID_CORES 0x001200D2
>>>> + /* Maximum Intel E-core and P-core availability */
>>>> +#define ASUS_WMI_DEVID_CORES_MAX 0x001200D3
>>>>    #define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099
>>>>    #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098
>>>>    #define ASUS_WMI_DEVID_APU_MEM 0x000600C1
>>>
>>>

^ permalink raw reply	[flat|nested] 39+ messages in thread

end of thread, other threads:[~2024-09-29  7:00 UTC | newest]

Thread overview: 39+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-26  9:29 [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Luke D. Jones
2024-09-26  9:29 ` [PATCH v4 1/9] platform/x86: asus-wmi: export symbols used for read/write WMI Luke D. Jones
2024-09-26 15:26   ` Mario Limonciello
2024-09-26  9:29 ` [PATCH v4 2/9] hid-asus: Add MODULE_IMPORT_NS(ASUS_WMI) Luke D. Jones
2024-09-26 11:54   ` Jiri Kosina
2024-09-26  9:29 ` [PATCH v4 3/9] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
2024-09-26 15:48   ` Mario Limonciello
2024-09-26 23:20     ` Luke Jones
2024-09-27 14:45       ` Mario Limonciello
2024-09-28  9:52         ` Luke Jones
2024-09-26 19:10   ` Markus Elfring
2024-09-26 21:50     ` Luke Jones
2024-09-27  6:09       ` [v4 " Markus Elfring
2024-09-27  7:05         ` Luke Jones
2024-09-27  7:24           ` Markus Elfring
2024-09-27  7:43             ` Luke Jones
2024-09-27  7:48               ` Julia Lawall
2024-09-26  9:29 ` [PATCH v4 4/9] platform/x86: asus-armoury: add panel_hd_mode attribute Luke D. Jones
2024-09-26 15:17   ` Mario Limonciello
2024-09-26 22:12     ` Luke Jones
2024-09-26  9:29 ` [PATCH v4 5/9] platform/x86: asus-armoury: add the ppt_* and nv_* tuning knobs Luke D. Jones
2024-09-26 15:22   ` Mario Limonciello
2024-09-26 22:39     ` Luke Jones
2024-09-26  9:29 ` [PATCH v4 6/9] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
2024-09-26  9:29 ` [PATCH v4 7/9] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
2024-09-26 15:25   ` Mario Limonciello
2024-09-26 22:14     ` Luke Jones
2024-09-26  9:29 ` [PATCH v4 8/9] platform/x86: asus-armoury: add core count control Luke D. Jones
2024-09-26 15:30   ` Mario Limonciello
2024-09-26 21:47     ` Luke Jones
2024-09-26 22:02       ` Mario Limonciello
2024-09-29  7:00         ` Luke Jones
2024-09-26  9:29 ` [PATCH v4 9/9] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
2024-09-26 14:56   ` Mario Limonciello
2024-09-26 22:04     ` Luke Jones
2024-09-28  0:13   ` kernel test robot
2024-09-28 21:02     ` Luke Jones
2024-09-26 14:50 ` [PATCH v4 0/9] platform/x86: introduce asus-armoury driver Mario Limonciello
2024-09-26 21:44   ` Luke Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).