* [PATCH v3 0/5] platform/x86: introduce asus-armoury driver
@ 2024-09-18 9:42 Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
` (4 more replies)
0 siblings, 5 replies; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
Luke D. Jones
This 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.
I am unsure of how best to handle the deprecation of attributes.
There's also some attributes that are obviously boolean but are using 0/1.
I'm unsure if I should change that.
And would it be best to move the asus stuff to a subdir now? Akin to the
Dell platform stuff.
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/
Luke D. Jones (5):
platform/x86: asus-armoury: move existing tunings to asus-armoury
module
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/platform/x86/Kconfig | 22 +
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/asus-armoury.c | 1056 +++++++++++++++++
drivers/platform/x86/asus-armoury.h | 255 ++++
drivers/platform/x86/asus-wmi.c | 203 +++-
drivers/platform/x86/asus-wmi.h | 14 +
include/linux/platform_data/x86/asus-wmi.h | 19 +
8 files changed, 1538 insertions(+), 49 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] 19+ messages in thread
* [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
@ 2024-09-18 9:42 ` Luke D. Jones
2024-09-18 15:37 ` Mario Limonciello
` (4 more replies)
2024-09-18 9:42 ` [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
` (3 subsequent siblings)
4 siblings, 5 replies; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
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.
Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
drivers/platform/x86/Kconfig | 14 +
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/asus-armoury.c | 702 +++++++++++++++++++++
drivers/platform/x86/asus-armoury.h | 209 ++++++
drivers/platform/x86/asus-wmi.c | 69 +-
drivers/platform/x86/asus-wmi.h | 14 +
include/linux/platform_data/x86/asus-wmi.h | 11 +
7 files changed, 1001 insertions(+), 19 deletions(-)
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 ddfccc226751..d13c4085c228 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 (firmware) Driver"
+ depends on ACPI_WMI
+ depends on ASUS_WMI
+ select FW_ATTR_CLASS
+ help
+ Say Y here if you have a WMI aware Asus laptop 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
@@ -276,6 +289,7 @@ config ASUS_WMI
depends on HOTPLUG_PCI
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on SERIO_I8042 || SERIO_I8042 = n
+ select ASUS_ARMOURY
select INPUT_SPARSEKMAP
select LEDS_CLASS
select NEW_LEDS
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..6e4507be0f05
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.c
@@ -0,0 +1,702 @@
+// 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
+/* New mode on some devices, define here to clarify remapping later */
+#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
+
+/* 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;
+
+ 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") ||
+ !strcmp(attr->attr.name, "panel_hd_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_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");
+
+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_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");
+
+/* 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 },
+
+ { &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 },
+ { &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)
+{
+ 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++) {
+ /* Do not show for the Ally devices as powersave is entirely unreliable on it */
+ if (armoury_attr_groups[i].wmi_devid == ASUS_WMI_DEVID_MCU_POWERSAVE &&
+ dmi_check_system(asus_rog_ally_device))
+ continue;
+
+ 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 ****************************************************************/
+
+/* 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;
+
+ 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..8bb75cf88305
--- /dev/null
+++ b/drivers/platform/x86/asus-armoury.h
@@ -0,0 +1,209 @@
+/* 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 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)
+{
+ 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 \
+ }
+
+/*
+ * 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_ */
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 08861792bddd..d265ef0d7aba 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -152,20 +152,6 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
static int throttle_thermal_policy_write(struct asus_wmi *);
-static const struct dmi_system_id asus_ally_mcu_quirk[] = {
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
- },
- },
- {
- .matches = {
- DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
- },
- },
- { },
-};
-
static bool ashs_present(void)
{
int i = 0;
@@ -386,7 +372,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)
@@ -550,12 +536,58 @@ 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);
+ *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
+
+ if (err)
+ return err;
+ /* Be explicit about retval */
+ 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,
@@ -4774,8 +4806,7 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
- asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
- && dmi_check_system(asus_ally_mcu_quirk);
+ asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE);
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index d02f15fd3482..c66e970b3674 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -86,4 +86,18 @@ struct asus_wmi_driver {
int asus_wmi_register_driver(struct asus_wmi_driver *driver);
void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
+static const struct dmi_system_id asus_rog_ally_device[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
+ },
+ },
+ { },
+};
+
#endif /* !_ASUS_WMI_H_ */
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 365e119bebaa..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
@@ -158,8 +159,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] 19+ messages in thread
* [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
@ 2024-09-18 9:42 ` Luke D. Jones
2024-09-18 15:39 ` Mario Limonciello
2024-09-18 9:42 ` [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
` (2 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
Luke D. Jones
Implement the dgpu TGP control under the asus-armoury module using the
fw_attributes class.
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 6e4507be0f05..176ab5f105dd 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 },
@@ -659,6 +675,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 8bb75cf88305..95f4b6d8ab6b 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); \
@@ -105,6 +119,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] 19+ messages in thread
* [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
@ 2024-09-18 9:42 ` Luke D. Jones
2024-09-18 15:44 ` Mario Limonciello
2024-09-18 9:42 ` [PATCH v3 4/5] platform/x86: asus-armoury: add core count control Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
4 siblings, 1 reply; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
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 176ab5f105dd..b276c42f98d8 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 256:
+ mem = 0;
+ break;
+ case 258:
+ mem = 1;
+ break;
+ case 259:
+ mem = 2;
+ break;
+ case 260:
+ mem = 3;
+ break;
+ case 261:
+ mem = 4;
+ break;
+ case 262:
+ /* This is out of order and looks wrong but is correct */
+ mem = 8;
+ break;
+ case 263:
+ mem = 5;
+ break;
+ case 264:
+ mem = 6;
+ break;
+ case 265:
+ 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 = 0;
+ break;
+ case 1:
+ mem = 258;
+ break;
+ case 2:
+ mem = 259;
+ break;
+ case 3:
+ mem = 260;
+ break;
+ case 4:
+ mem = 261;
+ break;
+ case 5:
+ mem = 263;
+ break;
+ case 6:
+ mem = 264;
+ break;
+ case 7:
+ mem = 265;
+ break;
+ case 8:
+ /* This is out of order and looks wrong but is correct */
+ mem = 262;
+ 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 the available system memory 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] 19+ messages in thread
* [PATCH v3 4/5] platform/x86: asus-armoury: add core count control
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
` (2 preceding siblings ...)
2024-09-18 9:42 ` [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
@ 2024-09-18 9:42 ` Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
4 siblings, 0 replies; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
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 b276c42f98d8..c3193756eb08 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 the available system memory 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 },
@@ -807,6 +1025,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 95f4b6d8ab6b..9e61d5cbe0c7 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -165,6 +165,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] 19+ messages in thread
* [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
` (3 preceding siblings ...)
2024-09-18 9:42 ` [PATCH v3 4/5] platform/x86: asus-armoury: add core count control Luke D. Jones
@ 2024-09-18 9:42 ` Luke D. Jones
2024-09-18 15:50 ` Mario Limonciello
4 siblings, 1 reply; 19+ messages in thread
From: Luke D. Jones @ 2024-09-18 9:42 UTC (permalink / raw)
To: platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary,
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 | 8 ++
drivers/platform/x86/asus-wmi.c | 134 ++++++++++++++----
3 files changed, 129 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 d13c4085c228..01f780d53793 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -301,6 +301,14 @@ config ASUS_WMI
To compile this driver as a module, choose M here: the module will
be called asus-wmi.
+config ASUS_WMI_BIOS
+ bool "BIOS option support in WMI platform (DEPRECATED)"
+ depends on ASUS_WMI
+ help
+ Say Y to expose the configurable BIOS options through the asus-wmi
+ driver. This can be used with or without the new asus-bios driver as
+ the options are the same but the asus-bios driver has more 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 d265ef0d7aba..edb00485e8c3 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -276,11 +276,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_BIOS)
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;
@@ -288,6 +289,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;
@@ -306,9 +310,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;
@@ -322,6 +323,15 @@ struct asus_wmi {
struct asus_wmi_driver *driver;
};
+#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
+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,
@@ -720,6 +730,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_BIOS)
static ssize_t charge_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -730,12 +741,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_BIOS)
static ssize_t dgpu_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -746,6 +761,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);
}
@@ -799,8 +816,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_BIOS)
static ssize_t egpu_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -811,6 +830,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);
}
@@ -867,8 +888,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_BIOS)
static ssize_t egpu_connected_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -879,12 +902,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_BIOS)
static ssize_t gpu_mux_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -895,6 +922,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);
}
@@ -953,6 +982,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,
@@ -1076,6 +1106,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
};
/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
static ssize_t ppt_pl2_sppt_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -1114,6 +1145,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);
@@ -1156,6 +1189,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);
@@ -1199,6 +1234,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);
@@ -1242,6 +1279,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);
@@ -1285,6 +1324,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);
@@ -1328,6 +1369,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);
@@ -1371,11 +1414,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_BIOS)
static ssize_t mcu_powersave_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -1386,6 +1433,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);
}
@@ -1421,6 +1470,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
return count;
}
static DEVICE_ATTR_RW(mcu_powersave);
+#endif
/* Battery ********************************************************************/
@@ -2294,6 +2344,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
}
/* Panel Overdrive ************************************************************/
+#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
static ssize_t panel_od_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2304,6 +2355,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);
}
@@ -2340,9 +2393,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_BIOS)
static ssize_t boot_sound_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2353,6 +2407,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);
}
@@ -2388,8 +2444,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_BIOS)
static ssize_t mini_led_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2420,6 +2478,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
}
}
+ asus_wmi_show_deprecated();
+
return sysfs_emit(buf, "%d\n", value);
}
@@ -2490,10 +2550,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 *********************************************************************/
@@ -3792,6 +3855,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
return 0;
}
+#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
static ssize_t throttle_thermal_policy_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3835,6 +3899,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)
@@ -4475,27 +4540,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_BIOS)
+ &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
};
@@ -4517,7 +4584,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_BIOS)
+ 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;
@@ -4555,6 +4626,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);
@@ -4795,6 +4867,7 @@ static int asus_wmi_add(struct platform_device *pdev)
goto fail_platform;
/* ensure defaults for tunables */
+ #if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
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_BIOS */
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] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
@ 2024-09-18 15:37 ` Mario Limonciello
2024-09-20 7:27 ` Luke Jones
2024-09-21 7:13 ` Christophe JAILLET
` (3 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2024-09-18 15:37 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary
On 9/18/2024 04:42, 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
> 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.
>
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---
> drivers/platform/x86/Kconfig | 14 +
> drivers/platform/x86/Makefile | 1 +
> drivers/platform/x86/asus-armoury.c | 702 +++++++++++++++++++++
> drivers/platform/x86/asus-armoury.h | 209 ++++++
> drivers/platform/x86/asus-wmi.c | 69 +-
> drivers/platform/x86/asus-wmi.h | 14 +
> include/linux/platform_data/x86/asus-wmi.h | 11 +
> 7 files changed, 1001 insertions(+), 19 deletions(-)
> create mode 100644 drivers/platform/x86/asus-armoury.c
> create mode 100644 drivers/platform/x86/asus-armoury.h
This is kinda a big patch that I feel might have done some justice to
split into smaller logical pieces. These are much easier to review.
For example:
1) You've clearly got 3 "groups" of attributes, maybe those should come
in a separate series each.
2) Some of the helper functions that are exported should be exported in
their own patches (for example asus_wmi_get_devstate_dsts)
3) panel_hd_mode is a new attribute not leveraged from asus-wmi AFAICT,
with a new define. It probably could have been it's own patch to "add
panel_hd_mode".
More comments inline below.
>
> diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> index ddfccc226751..d13c4085c228 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 (firmware) Driver"
This is a confusing title to me. What does it convey that just "Asus
Armoury driver" wouldn't?
> + depends on ACPI_WMI
> + depends on ASUS_WMI
> + select FW_ATTR_CLASS
> + help
> + Say Y here if you have a WMI aware Asus laptop and would like to use the
Doesn't it also cover handhelds? I'd probably just say "asus machine".
> + 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
> @@ -276,6 +289,7 @@ config ASUS_WMI
> depends on HOTPLUG_PCI
> depends on ACPI_VIDEO || ACPI_VIDEO = n
> depends on SERIO_I8042 || SERIO_I8042 = n
> + select ASUS_ARMOURY
Two problems:
1. Seems to be a circular depedency.
2. Selects can't have extra depends or selects (FW_ATTR_CLASS stands out).
I feel this select should just be droped.
> select INPUT_SPARSEKMAP
> select LEDS_CLASS
> select NEW_LEDS
> 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..6e4507be0f05
> --- /dev/null
> +++ b/drivers/platform/x86/asus-armoury.c
> @@ -0,0 +1,702 @@
> +// 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
> +/* New mode on some devices, define here to clarify remapping later */
The word "new" ages poorly, especially in comments.
> +#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
> +
> +/* 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;
> +
> + 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") ||
> + !strcmp(attr->attr.name, "panel_hd_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_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");
I go back and forth on the existence of tuning knobs for all these
values. As a tinkerer it's of course nice to see so many knobs.
However thinking about how this would be exposed to userspace and what
users will drag for a "slider" for performance it's really confusing.
Which knob is tuned? What's different for CPU vs platform? What's slow
vs fast?
As a result, I think I would rather see these (specifically) relegated
to debugfs attributes and instead export an ACPI platform profile. The
ACPI platform profile can then give users a clearer set of expectations; IE:
"power-saver", "balanced", "performance"
Bifurcating it this way will enable both audiences. The people who want
to drag a slider in a UI to save power or consume power can do so, and
those that know what all these mean and want to spend more time
tinkering can go to debugfs to do so.
But with this idea there would essentially be two sets of knobs that
change the same thing. So I think that if the debugfs knobs were tuned
away from the defaults the platform profile needs to be reset to an error.
> +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");
> +
> +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_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");
> +
> +/* 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 },
> +
> + { &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 },
> + { &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)
> +{
> + 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++) {
> + /* Do not show for the Ally devices as powersave is entirely unreliable on it */
> + if (armoury_attr_groups[i].wmi_devid == ASUS_WMI_DEVID_MCU_POWERSAVE &&
> + dmi_check_system(asus_rog_ally_device))
> + continue;
> +
> + 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 ****************************************************************/
> +
> +/* 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;
> +
> + 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..8bb75cf88305
> --- /dev/null
> +++ b/drivers/platform/x86/asus-armoury.h
> @@ -0,0 +1,209 @@
> +/* 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 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)
> +{
> + 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 \
> + }
> +
> +/*
> + * 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_ */
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 08861792bddd..d265ef0d7aba 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -152,20 +152,6 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
>
> static int throttle_thermal_policy_write(struct asus_wmi *);
>
> -static const struct dmi_system_id asus_ally_mcu_quirk[] = {
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> - },
> - },
> - {
> - .matches = {
> - DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> - },
> - },
> - { },
> -};
> -
> static bool ashs_present(void)
> {
> int i = 0;
> @@ -386,7 +372,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)
> @@ -550,12 +536,58 @@ 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);
> + *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
Shouldn't you only update this if no error? IE move to the end of the
function before return 0.
> +
> + if (err)
> + return err;
> + /* Be explicit about retval */
> + 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,
> @@ -4774,8 +4806,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
> asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
> asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
> - asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
> - && dmi_check_system(asus_ally_mcu_quirk);
> + asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE);
>
> if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
> asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
> diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
> index d02f15fd3482..c66e970b3674 100644
> --- a/drivers/platform/x86/asus-wmi.h
> +++ b/drivers/platform/x86/asus-wmi.h
> @@ -86,4 +86,18 @@ struct asus_wmi_driver {
> int asus_wmi_register_driver(struct asus_wmi_driver *driver);
> void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
>
> +static const struct dmi_system_id asus_rog_ally_device[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> + },
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> + },
> + },
> + { },
> +};
> +
> #endif /* !_ASUS_WMI_H_ */
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 365e119bebaa..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
> @@ -158,8 +159,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] 19+ messages in thread
* Re: [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control
2024-09-18 9:42 ` [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
@ 2024-09-18 15:39 ` Mario Limonciello
2024-09-21 6:57 ` Luke Jones
0 siblings, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2024-09-18 15:39 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary
On 9/18/2024 04:42, Luke D. Jones wrote:
> Implement the dgpu TGP control under the asus-armoury module using the
> fw_attributes class.
>
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
> ---
> 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 6e4507be0f05..176ab5f105dd 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 },
> @@ -659,6 +675,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 8bb75cf88305..95f4b6d8ab6b 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); \
> @@ -105,6 +119,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
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support
2024-09-18 9:42 ` [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
@ 2024-09-18 15:44 ` Mario Limonciello
2024-09-21 7:05 ` Luke Jones
0 siblings, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2024-09-18 15:44 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary
On 9/18/2024 04:42, 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>
> ---
> 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 176ab5f105dd..b276c42f98d8 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 256:
> + mem = 0;
> + break;
> + case 258:
> + mem = 1;
> + break;
> + case 259:
> + mem = 2;
> + break;
> + case 260:
> + mem = 3;
> + break;
> + case 261:
> + mem = 4;
> + break;
> + case 262:
> + /* This is out of order and looks wrong but is correct */
> + mem = 8;
> + break;
> + case 263:
> + mem = 5;
> + break;
> + case 264:
> + mem = 6;
> + break;
> + case 265:
> + 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 = 0;
> + break;
> + case 1:
> + mem = 258;
> + break;
> + case 2:
> + mem = 259;
> + break;
> + case 3:
> + mem = 260;
> + break;
> + case 4:
> + mem = 261;
> + break;
> + case 5:
> + mem = 263;
> + break;
> + case 6:
> + mem = 264;
> + break;
> + case 7:
> + mem = 265;
> + break;
> + case 8:
> + /* This is out of order and looks wrong but is correct */
> + mem = 262;
> + 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);
This doesn't seem right. If you requested "0", you just set APU memory
to 0GB?
> + 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");
What exactly is the unit for 0-8? It's obviously not a a multiple of
base memory, is it a multiple of an adder?
Is this changing the VRAM allocation? Like does 0 mean 256MB, 1 is 512 etc?
> +}
> +ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory 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] 19+ messages in thread
* Re: [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features
2024-09-18 9:42 ` [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
@ 2024-09-18 15:50 ` Mario Limonciello
2024-09-21 6:27 ` Luke Jones
0 siblings, 1 reply; 19+ messages in thread
From: Mario Limonciello @ 2024-09-18 15:50 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary
On 9/18/2024 04:42, 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>
> ---
> .../ABI/testing/sysfs-platform-asus-wmi | 17 +++
> drivers/platform/x86/Kconfig | 8 ++
> drivers/platform/x86/asus-wmi.c | 134 ++++++++++++++----
> 3 files changed, 129 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 d13c4085c228..01f780d53793 100644
> --- a/drivers/platform/x86/Kconfig
> +++ b/drivers/platform/x86/Kconfig
> @@ -301,6 +301,14 @@ config ASUS_WMI
> To compile this driver as a module, choose M here: the module will
> be called asus-wmi.
>
> +config ASUS_WMI_BIOS
Elsewhere in the kernel they add _DEPRECATED to the Kconfig name. Thoughts?
> + bool "BIOS option support in WMI platform (DEPRECATED)"
> + depends on ASUS_WMI
> + help
> + Say Y to expose the configurable BIOS options through the asus-wmi
> + driver. This can be used with or without the new asus-bios driver as
Isn't it asus-armoury?
> + the options are the same but the asus-bios driver has more 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 d265ef0d7aba..edb00485e8c3 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -276,11 +276,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_BIOS)
> 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;
> @@ -288,6 +289,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;
> @@ -306,9 +310,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;
> @@ -322,6 +323,15 @@ struct asus_wmi {
> struct asus_wmi_driver *driver;
> };
>
> +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> +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,
> @@ -720,6 +730,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_BIOS)
> static ssize_t charge_mode_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -730,12 +741,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_BIOS)
> static ssize_t dgpu_disable_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -746,6 +761,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);
> }
>
> @@ -799,8 +816,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_BIOS)
> static ssize_t egpu_enable_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -811,6 +830,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);
> }
>
> @@ -867,8 +888,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_BIOS)
> static ssize_t egpu_connected_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -879,12 +902,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_BIOS)
> static ssize_t gpu_mux_mode_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -895,6 +922,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);
> }
>
> @@ -953,6 +982,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,
> @@ -1076,6 +1106,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
> };
>
> /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> static ssize_t ppt_pl2_sppt_store(struct device *dev,
> struct device_attribute *attr,
> const char *buf, size_t count)
> @@ -1114,6 +1145,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);
> @@ -1156,6 +1189,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);
> @@ -1199,6 +1234,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);
> @@ -1242,6 +1279,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);
> @@ -1285,6 +1324,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);
> @@ -1328,6 +1369,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);
> @@ -1371,11 +1414,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_BIOS)
> static ssize_t mcu_powersave_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -1386,6 +1433,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);
> }
>
> @@ -1421,6 +1470,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
> return count;
> }
> static DEVICE_ATTR_RW(mcu_powersave);
> +#endif
>
> /* Battery ********************************************************************/
>
> @@ -2294,6 +2344,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
> }
>
> /* Panel Overdrive ************************************************************/
> +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> static ssize_t panel_od_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -2304,6 +2355,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);
> }
>
> @@ -2340,9 +2393,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_BIOS)
> static ssize_t boot_sound_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -2353,6 +2407,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);
> }
>
> @@ -2388,8 +2444,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_BIOS)
> static ssize_t mini_led_mode_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -2420,6 +2478,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
> }
> }
>
> + asus_wmi_show_deprecated();
> +
> return sysfs_emit(buf, "%d\n", value);
> }
>
> @@ -2490,10 +2550,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 *********************************************************************/
>
> @@ -3792,6 +3855,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
> return 0;
> }
>
> +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> static ssize_t throttle_thermal_policy_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> @@ -3835,6 +3899,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)
> @@ -4475,27 +4540,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_BIOS)
> + &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
> };
>
> @@ -4517,7 +4584,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_BIOS)
> + 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;
> @@ -4555,6 +4626,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);
> @@ -4795,6 +4867,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> goto fail_platform;
>
> /* ensure defaults for tunables */
> + #if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> 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_BIOS */
> 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] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 15:37 ` Mario Limonciello
@ 2024-09-20 7:27 ` Luke Jones
0 siblings, 0 replies; 19+ messages in thread
From: Luke Jones @ 2024-09-20 7:27 UTC (permalink / raw)
To: Mario Limonciello, platform-driver-x86
Cc: linux-kernel, Hans de Goede, Ilpo Järvinen, corentin.chary
On Thu, 19 Sep 2024, at 3:37 AM, Mario Limonciello wrote:
> On 9/18/2024 04:42, 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
> > 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.
> >
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> > ---
> > drivers/platform/x86/Kconfig | 14 +
> > drivers/platform/x86/Makefile | 1 +
> > drivers/platform/x86/asus-armoury.c | 702 +++++++++++++++++++++
> > drivers/platform/x86/asus-armoury.h | 209 ++++++
> > drivers/platform/x86/asus-wmi.c | 69 +-
> > drivers/platform/x86/asus-wmi.h | 14 +
> > include/linux/platform_data/x86/asus-wmi.h | 11 +
> > 7 files changed, 1001 insertions(+), 19 deletions(-)
> > create mode 100644 drivers/platform/x86/asus-armoury.c
> > create mode 100644 drivers/platform/x86/asus-armoury.h
>
> This is kinda a big patch that I feel might have done some justice to
> split into smaller logical pieces. These are much easier to review.
>
> For example:
>
> 1) You've clearly got 3 "groups" of attributes, maybe those should come
> in a separate series each.
> 2) Some of the helper functions that are exported should be exported in
> their own patches (for example asus_wmi_get_devstate_dsts)
> 3) panel_hd_mode is a new attribute not leveraged from asus-wmi AFAICT,
> with a new define. It probably could have been it's own patch to "add
> panel_hd_mode".
Good points yeah. I've split things in to smaller more easily digestible chunks now.
>
> More comments inline below.
>
> >
> > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
> > index ddfccc226751..d13c4085c228 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 (firmware) Driver"
>
> This is a confusing title to me. What does it convey that just "Asus
> Armoury driver" wouldn't?
Nothing much I guess. Changed now.
> > + depends on ACPI_WMI
> > + depends on ASUS_WMI
> > + select FW_ATTR_CLASS
> > + help
> > + Say Y here if you have a WMI aware Asus laptop and would like to use the
>
> Doesn't it also cover handhelds? I'd probably just say "asus machine".
Indeed yes, changed.
> > + 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
> > @@ -276,6 +289,7 @@ config ASUS_WMI
> > depends on HOTPLUG_PCI
> > depends on ACPI_VIDEO || ACPI_VIDEO = n
> > depends on SERIO_I8042 || SERIO_I8042 = n
> > + select ASUS_ARMOURY
>
> Two problems:
> 1. Seems to be a circular depedency.
> 2. Selects can't have extra depends or selects (FW_ATTR_CLASS stands out).
>
> I feel this select should just be droped.
Dropped. I wasn't entirely clear on how to use the "select" and "depends on". I think I much better understand how now especially given that I previously didn't know "select" does not honor the "depends on" of what it has selected.
> > select INPUT_SPARSEKMAP
> > select LEDS_CLASS
> > select NEW_LEDS
> > 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..6e4507be0f05
> > --- /dev/null
> > +++ b/drivers/platform/x86/asus-armoury.c
> > @@ -0,0 +1,702 @@
> > +// 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
> > +/* New mode on some devices, define here to clarify remapping later */
>
> The word "new" ages poorly, especially in comments.
Ack. Was a copy/paste from old asus_wmi code.
> > +#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
> > +
> > +/* 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;
> > +
> > + 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") ||
> > + !strcmp(attr->attr.name, "panel_hd_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_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");
>
> I go back and forth on the existence of tuning knobs for all these
> values. As a tinkerer it's of course nice to see so many knobs.
>
> However thinking about how this would be exposed to userspace and what
> users will drag for a "slider" for performance it's really confusing.
> Which knob is tuned? What's different for CPU vs platform? What's slow
> vs fast?
I fully understand the concern here and share it. But one thing I think that should be considered is that *most* users won't be going directly to the attributes, or even be aware of them. Those that do I would hope at least know what they are or the name/desc is enough to provide hints to find more info.
And then a usersapce app exposing these should explain what they are, and be much more usable. A tangible benefit of fw_attr class is that it makes userspace apps easier to do.
> As a result, I think I would rather see these (specifically) relegated
> to debugfs attributes and instead export an ACPI platform profile. The
> ACPI platform profile can then give users a clearer set of expectations; IE:
>
> "power-saver", "balanced", "performance"
>
> Bifurcating it this way will enable both audiences. The people who want
> to drag a slider in a UI to save power or consume power can do so, and
> those that know what all these mean and want to spend more time
> tinkering can go to debugfs to do so.
>
> But with this idea there would essentially be two sets of knobs that
> change the same thing. So I think that if the debugfs knobs were tuned
> away from the defaults the platform profile needs to be reset to an error.
This would at least address that changing these values deviates from the platform_profile, and also the system fan profile - so it puts the onus on the user to ensure the settings they use are safe to use.
My main concern is perhaps that I lose the easy to use fw_attr class. But I suppose I can also recreate the minimum of /path/attr_name/{min/max/default/current} without too much hassle.
Moving to debugfs:
pros:
- setting unsafe values moves responsibility to user
- simplifies things a little
- hides a possible danger from users
cons:
- setting unsafe values moves responsibility to user
- a userspace app then also takes on that responsibility
- loses the fw_attr class API
- makes it harder to access
For now these are moved to a new patch to make it easier to review as well as change.
> > +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");
> > +
> > +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_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");
> > +
> > +/* 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 },
> > +
> > + { &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 },
> > + { &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)
> > +{
> > + 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++) {
> > + /* Do not show for the Ally devices as powersave is entirely unreliable on it */
> > + if (armoury_attr_groups[i].wmi_devid == ASUS_WMI_DEVID_MCU_POWERSAVE &&
> > + dmi_check_system(asus_rog_ally_device))
> > + continue;
> > +
> > + 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 ****************************************************************/
> > +
> > +/* 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;
> > +
> > + 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..8bb75cf88305
> > --- /dev/null
> > +++ b/drivers/platform/x86/asus-armoury.h
> > @@ -0,0 +1,209 @@
> > +/* 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 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)
> > +{
> > + 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 \
> > + }
> > +
> > +/*
> > + * 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_ */
> > diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> > index 08861792bddd..d265ef0d7aba 100644
> > --- a/drivers/platform/x86/asus-wmi.c
> > +++ b/drivers/platform/x86/asus-wmi.c
> > @@ -152,20 +152,6 @@ static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
> >
> > static int throttle_thermal_policy_write(struct asus_wmi *);
> >
> > -static const struct dmi_system_id asus_ally_mcu_quirk[] = {
> > - {
> > - .matches = {
> > - DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> > - },
> > - },
> > - {
> > - .matches = {
> > - DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> > - },
> > - },
> > - { },
> > -};
> > -
> > static bool ashs_present(void)
> > {
> > int i = 0;
> > @@ -386,7 +372,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)
> > @@ -550,12 +536,58 @@ 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);
> > + *retval &= ~ASUS_WMI_DSTS_PRESENCE_BIT;
>
> Shouldn't you only update this if no error? IE move to the end of the
> function before return 0.
Yes, fixed.
> > +
> > + if (err)
> > + return err;
> > + /* Be explicit about retval */
> > + 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,
> > @@ -4774,8 +4806,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> > asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
> > asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
> > asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
> > - asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE)
> > - && dmi_check_system(asus_ally_mcu_quirk);
> > + asus->ally_mcu_usb_switch = acpi_has_method(NULL, ASUS_USB0_PWR_EC0_CSEE);
> >
> > if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE))
> > asus->mini_led_dev_id = ASUS_WMI_DEVID_MINI_LED_MODE;
> > diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
> > index d02f15fd3482..c66e970b3674 100644
> > --- a/drivers/platform/x86/asus-wmi.h
> > +++ b/drivers/platform/x86/asus-wmi.h
> > @@ -86,4 +86,18 @@ struct asus_wmi_driver {
> > int asus_wmi_register_driver(struct asus_wmi_driver *driver);
> > void asus_wmi_unregister_driver(struct asus_wmi_driver *driver);
> >
> > +static const struct dmi_system_id asus_rog_ally_device[] = {
> > + {
> > + .matches = {
> > + DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> > + },
> > + },
> > + {
> > + .matches = {
> > + DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> > + },
> > + },
> > + { },
> > +};
> > +
> > #endif /* !_ASUS_WMI_H_ */
> > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> > index 365e119bebaa..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
> > @@ -158,8 +159,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] 19+ messages in thread
* Re: [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features
2024-09-18 15:50 ` Mario Limonciello
@ 2024-09-21 6:27 ` Luke Jones
0 siblings, 0 replies; 19+ messages in thread
From: Luke Jones @ 2024-09-21 6:27 UTC (permalink / raw)
To: Mario Limonciello, platform-driver-x86
Cc: linux-kernel, Hans de Goede, Ilpo Järvinen, corentin.chary
On Thu, 19 Sep 2024, at 3:50 AM, Mario Limonciello wrote:
> On 9/18/2024 04:42, 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>
> > ---
> > .../ABI/testing/sysfs-platform-asus-wmi | 17 +++
> > drivers/platform/x86/Kconfig | 8 ++
> > drivers/platform/x86/asus-wmi.c | 134 ++++++++++++++----
> > 3 files changed, 129 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 d13c4085c228..01f780d53793 100644
> > --- a/drivers/platform/x86/Kconfig
> > +++ b/drivers/platform/x86/Kconfig
> > @@ -301,6 +301,14 @@ config ASUS_WMI
> > To compile this driver as a module, choose M here: the module will
> > be called asus-wmi.
> >
> > +config ASUS_WMI_BIOS
>
> Elsewhere in the kernel they add _DEPRECATED to the Kconfig name. Thoughts?
I've adjusted to suit. Seems wise.
> > + bool "BIOS option support in WMI platform (DEPRECATED)"
> > + depends on ASUS_WMI
> > + help
> > + Say Y to expose the configurable BIOS options through the asus-wmi
> > + driver. This can be used with or without the new asus-bios driver as
>
> Isn't it asus-armoury?
Yes, fixed.
> > + the options are the same but the asus-bios driver has more 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 d265ef0d7aba..edb00485e8c3 100644
> > --- a/drivers/platform/x86/asus-wmi.c
> > +++ b/drivers/platform/x86/asus-wmi.c
> > @@ -276,11 +276,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_BIOS)
> > 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;
> > @@ -288,6 +289,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;
> > @@ -306,9 +310,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;
> > @@ -322,6 +323,15 @@ struct asus_wmi {
> > struct asus_wmi_driver *driver;
> > };
> >
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> > +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,
> > @@ -720,6 +730,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_BIOS)
> > static ssize_t charge_mode_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -730,12 +741,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_BIOS)
> > static ssize_t dgpu_disable_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -746,6 +761,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);
> > }
> >
> > @@ -799,8 +816,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_BIOS)
> > static ssize_t egpu_enable_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -811,6 +830,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);
> > }
> >
> > @@ -867,8 +888,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_BIOS)
> > static ssize_t egpu_connected_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -879,12 +902,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_BIOS)
> > static ssize_t gpu_mux_mode_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -895,6 +922,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);
> > }
> >
> > @@ -953,6 +982,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,
> > @@ -1076,6 +1106,7 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
> > };
> >
> > /* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> > static ssize_t ppt_pl2_sppt_store(struct device *dev,
> > struct device_attribute *attr,
> > const char *buf, size_t count)
> > @@ -1114,6 +1145,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);
> > @@ -1156,6 +1189,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);
> > @@ -1199,6 +1234,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);
> > @@ -1242,6 +1279,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);
> > @@ -1285,6 +1324,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);
> > @@ -1328,6 +1369,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);
> > @@ -1371,11 +1414,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_BIOS)
> > static ssize_t mcu_powersave_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -1386,6 +1433,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);
> > }
> >
> > @@ -1421,6 +1470,7 @@ static ssize_t mcu_powersave_store(struct device *dev,
> > return count;
> > }
> > static DEVICE_ATTR_RW(mcu_powersave);
> > +#endif
> >
> > /* Battery ********************************************************************/
> >
> > @@ -2294,6 +2344,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
> > }
> >
> > /* Panel Overdrive ************************************************************/
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> > static ssize_t panel_od_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -2304,6 +2355,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);
> > }
> >
> > @@ -2340,9 +2393,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_BIOS)
> > static ssize_t boot_sound_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -2353,6 +2407,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);
> > }
> >
> > @@ -2388,8 +2444,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_BIOS)
> > static ssize_t mini_led_mode_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -2420,6 +2478,8 @@ static ssize_t mini_led_mode_show(struct device *dev,
> > }
> > }
> >
> > + asus_wmi_show_deprecated();
> > +
> > return sysfs_emit(buf, "%d\n", value);
> > }
> >
> > @@ -2490,10 +2550,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 *********************************************************************/
> >
> > @@ -3792,6 +3855,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
> > return 0;
> > }
> >
> > +#if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> > static ssize_t throttle_thermal_policy_show(struct device *dev,
> > struct device_attribute *attr, char *buf)
> > {
> > @@ -3835,6 +3899,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)
> > @@ -4475,27 +4540,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_BIOS)
> > + &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
> > };
> >
> > @@ -4517,7 +4584,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_BIOS)
> > + 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;
> > @@ -4555,6 +4626,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);
> > @@ -4795,6 +4867,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> > goto fail_platform;
> >
> > /* ensure defaults for tunables */
> > + #if IS_ENABLED(CONFIG_ASUS_WMI_BIOS)
> > 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_BIOS */
> > 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] 19+ messages in thread
* Re: [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control
2024-09-18 15:39 ` Mario Limonciello
@ 2024-09-21 6:57 ` Luke Jones
0 siblings, 0 replies; 19+ messages in thread
From: Luke Jones @ 2024-09-21 6:57 UTC (permalink / raw)
To: Mario Limonciello, platform-driver-x86
Cc: linux-kernel, Hans de Goede, Ilpo Järvinen, corentin.chary
On Thu, 19 Sep 2024, at 3:39 AM, Mario Limonciello wrote:
> On 9/18/2024 04:42, Luke D. Jones wrote:
> > Implement the dgpu TGP control under the asus-armoury module using the
> > fw_attributes class.
> >
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
>
> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Ack
> > ---
> > 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 6e4507be0f05..176ab5f105dd 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 },
> > @@ -659,6 +675,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 8bb75cf88305..95f4b6d8ab6b 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); \
> > @@ -105,6 +119,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
>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support
2024-09-18 15:44 ` Mario Limonciello
@ 2024-09-21 7:05 ` Luke Jones
0 siblings, 0 replies; 19+ messages in thread
From: Luke Jones @ 2024-09-21 7:05 UTC (permalink / raw)
To: Mario Limonciello, platform-driver-x86
Cc: linux-kernel, Hans de Goede, Ilpo Järvinen, corentin.chary
On Thu, 19 Sep 2024, at 3:44 AM, Mario Limonciello wrote:
> On 9/18/2024 04:42, 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>
> > ---
> > 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 176ab5f105dd..b276c42f98d8 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 256:
> > + mem = 0;
> > + break;
> > + case 258:
> > + mem = 1;
> > + break;
> > + case 259:
> > + mem = 2;
> > + break;
> > + case 260:
> > + mem = 3;
> > + break;
> > + case 261:
> > + mem = 4;
> > + break;
> > + case 262:
> > + /* This is out of order and looks wrong but is correct */
> > + mem = 8;
> > + break;
> > + case 263:
> > + mem = 5;
> > + break;
> > + case 264:
> > + mem = 6;
> > + break;
> > + case 265:
> > + 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 = 0;
> > + break;
> > + case 1:
> > + mem = 258;
> > + break;
> > + case 2:
> > + mem = 259;
> > + break;
> > + case 3:
> > + mem = 260;
> > + break;
> > + case 4:
> > + mem = 261;
> > + break;
> > + case 5:
> > + mem = 263;
> > + break;
> > + case 6:
> > + mem = 264;
> > + break;
> > + case 7:
> > + mem = 265;
> > + break;
> > + case 8:
> > + /* This is out of order and looks wrong but is correct */
> > + mem = 262;
> > + 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);
>
> This doesn't seem right. If you requested "0", you just set APU memory
> to 0GB?
Yep.. I know it seems wrong but it's true. GHelper on windows does the same thing https://github.com/seerge/g-helper/blob/ab08bd8ab45774b3e1961ddff69b6281a2f6e733/app/AsusACPI.cs#L666
> > + 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");
>
> What exactly is the unit for 0-8? It's obviously not a a multiple of
> base memory, is it a multiple of an adder?
>
> Is this changing the VRAM allocation? Like does 0 mean 256MB, 1 is 512 etc?
There is a log entry above that clarifying it but I thought I'd done the same here. Fixed now.
> > +}
> > +ATTR_GROUP_ENUM_CUSTOM(apu_mem, "apu_mem", "Set the available system memory 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] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
2024-09-18 15:37 ` Mario Limonciello
@ 2024-09-21 7:13 ` Christophe JAILLET
2024-09-21 9:49 ` Luke Jones
2024-09-21 17:48 ` kernel test robot
` (2 subsequent siblings)
4 siblings, 1 reply; 19+ messages in thread
From: Christophe JAILLET @ 2024-09-21 7:13 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: linux-kernel, hdegoede, ilpo.jarvinen, corentin.chary
Le 18/09/2024 à 11:42, Luke D. Jones a écrit :
> 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.
>
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
Hi,
a few nitpick below, should it help.
> +/* 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 \
It would be more readable if ", NULL" was on its own line, IMHO.
> + }; \
> + 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 \
It would be more readable if ", NULL" was on its own line, IMHO.
> + }; \
> + static const struct attribute_group _attrname##_attr_group = { \
> + .name = _fsname, .attrs = _attrname##_attrs \
> + }
...
> +static const struct dmi_system_id asus_rog_ally_device[] = {
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> + },
> + },
> + {
> + .matches = {
> + DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> + },
> + },
> + { },
I think that an ending comma is not expected after a terminator.
> +};
> +
> #endif /* !_ASUS_WMI_H_ */
...
CJ
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-21 7:13 ` Christophe JAILLET
@ 2024-09-21 9:49 ` Luke Jones
0 siblings, 0 replies; 19+ messages in thread
From: Luke Jones @ 2024-09-21 9:49 UTC (permalink / raw)
To: Christophe JAILLET, platform-driver-x86
Cc: linux-kernel, Hans de Goede, Ilpo Järvinen, corentin.chary
On Sat, 21 Sep 2024, at 7:13 PM, Christophe JAILLET wrote:
> Le 18/09/2024 à 11:42, Luke D. Jones a écrit :
> > 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.
> >
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
>
> Hi,
>
> a few nitpick below, should it help.
every review is helpful, thank you :)
> > +/* 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 \
>
> It would be more readable if ", NULL" was on its own line, IMHO.
Ah yes, I didn't see this. Fixed, plus all following.
> > + }; \
> > + 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 \
>
> It would be more readable if ", NULL" was on its own line, IMHO.
>
> > + }; \
> > + static const struct attribute_group _attrname##_attr_group = { \
> > + .name = _fsname, .attrs = _attrname##_attrs \
> > + }
>
> ...
>
> > +static const struct dmi_system_id asus_rog_ally_device[] = {
> > + {
> > + .matches = {
> > + DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
> > + },
> > + },
> > + {
> > + .matches = {
> > + DMI_MATCH(DMI_BOARD_NAME, "RC72L"),
> > + },
> > + },
> > + { },
>
> I think that an ending comma is not expected after a terminator.
Never really been clear on this myself. A massive amount of other code does include the comma so that's what I followed. And then a massive amount of other code uses the opposite so I could follow that too.. but I work in most of the asus stuff and it looks like that's what is common there so I'll remove the comma.
Many thanks for taking the time to review.
> > +};
> > +
> > #endif /* !_ASUS_WMI_H_ */
>
> ...
>
> CJ
>
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
2024-09-18 15:37 ` Mario Limonciello
2024-09-21 7:13 ` Christophe JAILLET
@ 2024-09-21 17:48 ` kernel test robot
2024-09-21 20:12 ` kernel test robot
2024-09-22 1:33 ` kernel test robot
4 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2024-09-21 17:48 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: llvm, oe-kbuild-all, linux-kernel, hdegoede, ilpo.jarvinen,
corentin.chary, Luke D. Jones
Hi Luke,
kernel test robot noticed the following build errors:
[auto build test ERROR on next-20240918]
[also build test ERROR on v6.11]
[cannot apply to linus/master v6.11 v6.11-rc7 v6.11-rc6]
[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-armoury-move-existing-tunings-to-asus-armoury-module/20240918-174540
base: next-20240918
patch link: https://lore.kernel.org/r/20240918094250.82430-2-luke%40ljones.dev
patch subject: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
config: x86_64-rhel-8.3-rust (https://download.01.org/0day-ci/archive/20240922/202409220126.kUWmewio-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/20240922/202409220126.kUWmewio-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/202409220126.kUWmewio-lkp@intel.com/
All error/warnings (new ones prefixed by >>, old ones prefixed by <<):
>> drivers/platform/x86/asus-armoury.c:161: warning: Function parameter or struct member 'attr' not described in 'attr_int_store'
>> drivers/platform/x86/asus-armoury.c:161: warning: Excess function parameter 'kobj_attribute' description in 'attr_int_store'
--
>> ERROR: modpost: module hid-asus uses symbol asus_wmi_evaluate_method from namespace ASUS_WMI, but does not import it.
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
` (2 preceding siblings ...)
2024-09-21 17:48 ` kernel test robot
@ 2024-09-21 20:12 ` kernel test robot
2024-09-22 1:33 ` kernel test robot
4 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2024-09-21 20:12 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: oe-kbuild-all, linux-kernel, hdegoede, ilpo.jarvinen,
corentin.chary, Luke D. Jones
Hi Luke,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20240918]
[also build test WARNING on v6.11]
[cannot apply to linus/master v6.11 v6.11-rc7 v6.11-rc6]
[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-armoury-move-existing-tunings-to-asus-armoury-module/20240918-174540
base: next-20240918
patch link: https://lore.kernel.org/r/20240918094250.82430-2-luke%40ljones.dev
patch subject: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
config: i386-allmodconfig (https://download.01.org/0day-ci/archive/20240922/202409220341.XurF2eMb-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240922/202409220341.XurF2eMb-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/202409220341.XurF2eMb-lkp@intel.com/
All warnings (new ones prefixed by >>, old ones prefixed by <<):
>> WARNING: modpost: module hid-asus uses symbol asus_wmi_evaluate_method from namespace ASUS_WMI, but does not import it.
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for GET_FREE_REGION
Depends on [n]: SPARSEMEM [=n]
Selected by [m]:
- RESOURCE_KUNIT_TEST [=m] && RUNTIME_TESTING_MENU [=y] && KUNIT [=m]
WARNING: unmet direct dependencies detected for OMAP2PLUS_MBOX
Depends on [n]: MAILBOX [=y] && (ARCH_OMAP2PLUS || ARCH_K3)
Selected by [m]:
- TI_K3_M4_REMOTEPROC [=m] && REMOTEPROC [=y] && (ARCH_K3 || COMPILE_TEST [=y])
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
` (3 preceding siblings ...)
2024-09-21 20:12 ` kernel test robot
@ 2024-09-22 1:33 ` kernel test robot
4 siblings, 0 replies; 19+ messages in thread
From: kernel test robot @ 2024-09-22 1:33 UTC (permalink / raw)
To: Luke D. Jones, platform-driver-x86
Cc: oe-kbuild-all, linux-kernel, hdegoede, ilpo.jarvinen,
corentin.chary, Luke D. Jones
Hi Luke,
kernel test robot noticed the following build warnings:
[auto build test WARNING on next-20240918]
[also build test WARNING on v6.11]
[cannot apply to linus/master v6.11 v6.11-rc7 v6.11-rc6]
[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-armoury-move-existing-tunings-to-asus-armoury-module/20240918-174540
base: next-20240918
patch link: https://lore.kernel.org/r/20240918094250.82430-2-luke%40ljones.dev
patch subject: [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20240922/202409220913.WEYnCgBL-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240922/202409220913.WEYnCgBL-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/202409220913.WEYnCgBL-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from drivers/platform/x86/asus-armoury.c:23:
>> include/linux/platform_data/x86/asus-wmi.h:182:35: warning: 'asus_use_hid_led_dmi_ids' defined but not used [-Wunused-const-variable=]
182 | static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
| ^~~~~~~~~~~~~~~~~~~~~~~~
--
In file included from drivers/platform/x86/asus-wmi.c:45:
>> drivers/platform/x86/asus-wmi.h:89:35: warning: 'asus_rog_ally_device' defined but not used [-Wunused-const-variable=]
89 | static const struct dmi_system_id asus_rog_ally_device[] = {
| ^~~~~~~~~~~~~~~~~~~~
Kconfig warnings: (for reference only)
WARNING: unmet direct dependencies detected for GET_FREE_REGION
Depends on [n]: SPARSEMEM [=n]
Selected by [y]:
- RESOURCE_KUNIT_TEST [=y] && RUNTIME_TESTING_MENU [=y] && KUNIT [=y]
WARNING: unmet direct dependencies detected for OMAP2PLUS_MBOX
Depends on [n]: MAILBOX [=y] && (ARCH_OMAP2PLUS || ARCH_K3)
Selected by [y]:
- TI_K3_M4_REMOTEPROC [=y] && REMOTEPROC [=y] && (ARCH_K3 || COMPILE_TEST [=y])
vim +/asus_use_hid_led_dmi_ids +182 include/linux/platform_data/x86/asus-wmi.h
ffb6ce7086ee2d Daniel Drake 2018-10-09 180
a720dee5e03923 Luke D. Jones 2024-07-13 181 /* To be used by both hid-asus and asus-wmi to determine which controls kbd_brightness */
a720dee5e03923 Luke D. Jones 2024-07-13 @182 static const struct dmi_system_id asus_use_hid_led_dmi_ids[] = {
a720dee5e03923 Luke D. Jones 2024-07-13 183 {
a720dee5e03923 Luke D. Jones 2024-07-13 184 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 185 DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Zephyrus"),
a720dee5e03923 Luke D. Jones 2024-07-13 186 },
a720dee5e03923 Luke D. Jones 2024-07-13 187 },
a720dee5e03923 Luke D. Jones 2024-07-13 188 {
a720dee5e03923 Luke D. Jones 2024-07-13 189 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 190 DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Strix"),
a720dee5e03923 Luke D. Jones 2024-07-13 191 },
a720dee5e03923 Luke D. Jones 2024-07-13 192 },
a720dee5e03923 Luke D. Jones 2024-07-13 193 {
a720dee5e03923 Luke D. Jones 2024-07-13 194 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 195 DMI_MATCH(DMI_PRODUCT_FAMILY, "ROG Flow"),
a720dee5e03923 Luke D. Jones 2024-07-13 196 },
a720dee5e03923 Luke D. Jones 2024-07-13 197 },
a720dee5e03923 Luke D. Jones 2024-07-13 198 {
a720dee5e03923 Luke D. Jones 2024-07-13 199 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 200 DMI_MATCH(DMI_BOARD_NAME, "GA403U"),
a720dee5e03923 Luke D. Jones 2024-07-13 201 },
a720dee5e03923 Luke D. Jones 2024-07-13 202 },
a720dee5e03923 Luke D. Jones 2024-07-13 203 {
a720dee5e03923 Luke D. Jones 2024-07-13 204 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 205 DMI_MATCH(DMI_BOARD_NAME, "GU605M"),
a720dee5e03923 Luke D. Jones 2024-07-13 206 },
a720dee5e03923 Luke D. Jones 2024-07-13 207 },
a720dee5e03923 Luke D. Jones 2024-07-13 208 {
a720dee5e03923 Luke D. Jones 2024-07-13 209 .matches = {
a720dee5e03923 Luke D. Jones 2024-07-13 210 DMI_MATCH(DMI_BOARD_NAME, "RC71L"),
a720dee5e03923 Luke D. Jones 2024-07-13 211 },
a720dee5e03923 Luke D. Jones 2024-07-13 212 },
a720dee5e03923 Luke D. Jones 2024-07-13 213 { },
a720dee5e03923 Luke D. Jones 2024-07-13 214 };
a720dee5e03923 Luke D. Jones 2024-07-13 215
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2024-09-22 1:34 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-18 9:42 [PATCH v3 0/5] platform/x86: introduce asus-armoury driver Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 1/5] platform/x86: asus-armoury: move existing tunings to asus-armoury module Luke D. Jones
2024-09-18 15:37 ` Mario Limonciello
2024-09-20 7:27 ` Luke Jones
2024-09-21 7:13 ` Christophe JAILLET
2024-09-21 9:49 ` Luke Jones
2024-09-21 17:48 ` kernel test robot
2024-09-21 20:12 ` kernel test robot
2024-09-22 1:33 ` kernel test robot
2024-09-18 9:42 ` [PATCH v3 2/5] platform/x86: asus-armoury: add dgpu tgp control Luke D. Jones
2024-09-18 15:39 ` Mario Limonciello
2024-09-21 6:57 ` Luke Jones
2024-09-18 9:42 ` [PATCH v3 3/5] platform/x86: asus-armoury: add apu-mem control support Luke D. Jones
2024-09-18 15:44 ` Mario Limonciello
2024-09-21 7:05 ` Luke Jones
2024-09-18 9:42 ` [PATCH v3 4/5] platform/x86: asus-armoury: add core count control Luke D. Jones
2024-09-18 9:42 ` [PATCH v3 5/5] platform/x86: asus-wmi: deprecate bios features Luke D. Jones
2024-09-18 15:50 ` Mario Limonciello
2024-09-21 6:27 ` Luke Jones
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox