diff mbox series

[7/9] platform/x86: asus-wmi: add enable/disable CPU cores

Message ID 20240528013626.14066-8-luke@ljones.dev (mailing list archive)
State Changes Requested, archived
Headers show
Series platform-x86-asus-wmi: multiple fixes, improvements, features | expand

Commit Message

Luke Jones May 28, 2024, 1:36 a.m. UTC
Exposes the WMI functions for enable/disable of performance and
efficiency cores on some laptop models (largely Intel only).

Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
 .../ABI/testing/sysfs-platform-asus-wmi       | 19 ++++++++
 drivers/platform/x86/asus-wmi.c               | 45 +++++++++++++++++++
 include/linux/platform_data/x86/asus-wmi.h    |  5 +++
 3 files changed, 69 insertions(+)

Comments

Ilpo Järvinen May 28, 2024, 9:27 a.m. UTC | #1
Hi,

Hans, please check my question below.

On Tue, 28 May 2024, Luke D. Jones wrote:

> Exposes the WMI functions for enable/disable of performance and
> efficiency cores on some laptop models (largely Intel only).
> 
> Signed-off-by: Luke D. Jones <luke@ljones.dev>
> ---

> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 3b4eeea75b7b..ac881e72e374 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -226,3 +226,22 @@ Description:
>  		Set panel to UHD or FHD mode
>  			* 0 - UHD,
>  			* 1 - FHD
> +
> +What:		/sys/devices/platform/<platform>/cores_enabled
> +Date:		Jun 2024
> +KernelVersion:	6.11
> +Contact:	"Luke Jones" <luke@ljones.dev>
> +Description:
> +		Enable/disable efficiency and performance cores. The format is
> +		0x[E][P] where [E] is the efficiency core count, and [P] is
> +		the perfromance core count. If the core count is a single digit

performance

> +		it is preceded by a 0 such as 0x0406; E=4, P=6, 0x1006; E=10, P=6
> +
> +What:		/sys/devices/platform/<platform>/cores_max
> +Date:		Jun 2024
> +KernelVersion:	6.11
> +Contact:	"Luke Jones" <luke@ljones.dev>
> +Description:
> +		Show the maximum performance and efficiency core countin format
> +		0x[E][P] where [E] is the efficiency core count, and [P] is
> +		the perfromance core count.

performance

> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 4b045f1828f1..f62a36dfcd4b 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -815,6 +815,46 @@ static ssize_t panel_fhd_store(struct device *dev,
>  WMI_SIMPLE_SHOW(panel_fhd, "%d\n", ASUS_WMI_DEVID_PANEL_FHD);
>  static DEVICE_ATTR_RW(panel_fhd);
>  
> +/* Efficiency and Performance core control **********************************/
> +static ssize_t cores_enabled_store(struct device *dev,
> +				    struct device_attribute *attr,
> +				    const char *buf, size_t count)
> +{
> +	struct asus_wmi *asus = dev_get_drvdata(dev);
> +	int result, err;
> +	u32 cores, max;
> +
> +	result = kstrtou32(buf, 16, &cores);
> +	if (result)
> +		return result;
> +
> +	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CORES_MAX, &max);
> +	if (err < 0)
> +		return err;
> +
> +	if (cores > max) {

This only checks one part of it and the P part can contain whatever 
garbage as long as E is small enough?

But I'm not sure if it's good idea to have these two changed through the 
same sysfs file, I'm leaning more on that it would be better to split the 
interface for P and E.

Hans, what you think about this?

> +		pr_warn("Core count 0x%x exceeds max: 0x%x\n", cores, max);
> +		return -EIO;
> +	}
> +
> +	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES_SET, cores, &result);
> +	if (err) {
> +		pr_warn("Failed to set cores_enabled: %d\n", err);
> +		return err;
> +	}
> +
> +	pr_info("Enabled core count changed, reboot required\n");
> +	sysfs_notify(&asus->platform_device->dev.kobj, NULL, "cores_enabled");
> +
> +	return count;
> +}

> @@ -4131,6 +4173,9 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
>  		devid = ASUS_WMI_DEVID_PANEL_OD;
>  	else if (attr == &dev_attr_panel_fhd.attr)
>  		devid = ASUS_WMI_DEVID_PANEL_FHD;
> +	else if (attr == &dev_attr_cores_enabled.attr
> +		|| attr == &dev_attr_cores_max.attr)

Wrong alignment.
Luke Jones May 28, 2024, 9:37 p.m. UTC | #2
On Tue, 28 May 2024, at 9:27 PM, Ilpo Järvinen wrote:
> Hi,
> 
> Hans, please check my question below.
> 
> On Tue, 28 May 2024, Luke D. Jones wrote:
> 
> > Exposes the WMI functions for enable/disable of performance and
> > efficiency cores on some laptop models (largely Intel only).
> > 
> > Signed-off-by: Luke D. Jones <luke@ljones.dev>
> > ---
> 
> > diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > index 3b4eeea75b7b..ac881e72e374 100644
> > --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> > @@ -226,3 +226,22 @@ Description:
> >  Set panel to UHD or FHD mode
> >  * 0 - UHD,
> >  * 1 - FHD
> > +
> > +What: /sys/devices/platform/<platform>/cores_enabled
> > +Date: Jun 2024
> > +KernelVersion: 6.11
> > +Contact: "Luke Jones" <luke@ljones.dev>
> > +Description:
> > + Enable/disable efficiency and performance cores. The format is
> > + 0x[E][P] where [E] is the efficiency core count, and [P] is
> > + the perfromance core count. If the core count is a single digit
> 
> performance
> 
> > + it is preceded by a 0 such as 0x0406; E=4, P=6, 0x1006; E=10, P=6
> > +
> > +What: /sys/devices/platform/<platform>/cores_max
> > +Date: Jun 2024
> > +KernelVersion: 6.11
> > +Contact: "Luke Jones" <luke@ljones.dev>
> > +Description:
> > + Show the maximum performance and efficiency core countin format
> > + 0x[E][P] where [E] is the efficiency core count, and [P] is
> > + the perfromance core count.
> 
> performance
> 
> > diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> > index 4b045f1828f1..f62a36dfcd4b 100644
> > --- a/drivers/platform/x86/asus-wmi.c
> > +++ b/drivers/platform/x86/asus-wmi.c
> > @@ -815,6 +815,46 @@ static ssize_t panel_fhd_store(struct device *dev,
> >  WMI_SIMPLE_SHOW(panel_fhd, "%d\n", ASUS_WMI_DEVID_PANEL_FHD);
> >  static DEVICE_ATTR_RW(panel_fhd);
> >  
> > +/* Efficiency and Performance core control **********************************/
> > +static ssize_t cores_enabled_store(struct device *dev,
> > +     struct device_attribute *attr,
> > +     const char *buf, size_t count)
> > +{
> > + struct asus_wmi *asus = dev_get_drvdata(dev);
> > + int result, err;
> > + u32 cores, max;
> > +
> > + result = kstrtou32(buf, 16, &cores);
> > + if (result)
> > + return result;
> > +
> > + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CORES_MAX, &max);
> > + if (err < 0)
> > + return err;
> > +
> > + if (cores > max) {
> 
> This only checks one part of it and the P part can contain whatever 
> garbage as long as E is small enough?
> 
> But I'm not sure if it's good idea to have these two changed through the 
> same sysfs file, I'm leaning more on that it would be better to split the 
> interface for P and E.
> 
> Hans, what you think about this?

I'm inclined to agree. It's no issue to change it.

Ack all reviews. I'll work through them over the week but with a lower priority while I await both yours and Hans response in other replies with Mario regarding the firmware_attributes change/use.

> 
> > + pr_warn("Core count 0x%x exceeds max: 0x%x\n", cores, max);
> > + return -EIO;
> > + }
> > +
> > + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES_SET, cores, &result);
> > + if (err) {
> > + pr_warn("Failed to set cores_enabled: %d\n", err);
> > + return err;
> > + }
> > +
> > + pr_info("Enabled core count changed, reboot required\n");
> > + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "cores_enabled");
> > +
> > + return count;
> > +}
> 
> > @@ -4131,6 +4173,9 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> >  devid = ASUS_WMI_DEVID_PANEL_OD;
> >  else if (attr == &dev_attr_panel_fhd.attr)
> >  devid = ASUS_WMI_DEVID_PANEL_FHD;
> > + else if (attr == &dev_attr_cores_enabled.attr
> > + || attr == &dev_attr_cores_max.attr)
> 
> Wrong alignment.
> 
> -- 
> i.
> 
>
diff mbox series

Patch

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 3b4eeea75b7b..ac881e72e374 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -226,3 +226,22 @@  Description:
 		Set panel to UHD or FHD mode
 			* 0 - UHD,
 			* 1 - FHD
+
+What:		/sys/devices/platform/<platform>/cores_enabled
+Date:		Jun 2024
+KernelVersion:	6.11
+Contact:	"Luke Jones" <luke@ljones.dev>
+Description:
+		Enable/disable efficiency and performance cores. The format is
+		0x[E][P] where [E] is the efficiency core count, and [P] is
+		the perfromance core count. If the core count is a single digit
+		it is preceded by a 0 such as 0x0406; E=4, P=6, 0x1006; E=10, P=6
+
+What:		/sys/devices/platform/<platform>/cores_max
+Date:		Jun 2024
+KernelVersion:	6.11
+Contact:	"Luke Jones" <luke@ljones.dev>
+Description:
+		Show the maximum performance and efficiency core countin format
+		0x[E][P] where [E] is the efficiency core count, and [P] is
+		the perfromance core count.
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 4b045f1828f1..f62a36dfcd4b 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -815,6 +815,46 @@  static ssize_t panel_fhd_store(struct device *dev,
 WMI_SIMPLE_SHOW(panel_fhd, "%d\n", ASUS_WMI_DEVID_PANEL_FHD);
 static DEVICE_ATTR_RW(panel_fhd);
 
+/* Efficiency and Performance core control **********************************/
+static ssize_t cores_enabled_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct asus_wmi *asus = dev_get_drvdata(dev);
+	int result, err;
+	u32 cores, max;
+
+	result = kstrtou32(buf, 16, &cores);
+	if (result)
+		return result;
+
+	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CORES_MAX, &max);
+	if (err < 0)
+		return err;
+
+	if (cores > max) {
+		pr_warn("Core count 0x%x exceeds max: 0x%x\n", cores, max);
+		return -EIO;
+	}
+
+	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_CORES_SET, cores, &result);
+	if (err) {
+		pr_warn("Failed to set cores_enabled: %d\n", err);
+		return err;
+	}
+
+	pr_info("Enabled core count changed, reboot required\n");
+	sysfs_notify(&asus->platform_device->dev.kobj, NULL, "cores_enabled");
+
+	return count;
+}
+
+WMI_SIMPLE_SHOW(cores_enabled, "0x%x\n", ASUS_WMI_DEVID_CORES_SET);
+static DEVICE_ATTR_RW(cores_enabled);
+
+WMI_SIMPLE_SHOW(cores_max, "0x%x\n", ASUS_WMI_DEVID_CORES_MAX);
+static DEVICE_ATTR_RO(cores_max);
+
 /* Tablet mode ****************************************************************/
 
 static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
@@ -4058,6 +4098,8 @@  static struct attribute *platform_attributes[] = {
 	&dev_attr_boot_sound.attr,
 	&dev_attr_panel_od.attr,
 	&dev_attr_panel_fhd.attr,
+	&dev_attr_cores_enabled.attr,
+	&dev_attr_cores_max.attr,
 	&dev_attr_mini_led_mode.attr,
 	&dev_attr_available_mini_led_mode.attr,
 	NULL
@@ -4131,6 +4173,9 @@  static umode_t asus_sysfs_is_visible(struct kobject *kobj,
 		devid = ASUS_WMI_DEVID_PANEL_OD;
 	else if (attr == &dev_attr_panel_fhd.attr)
 		devid = ASUS_WMI_DEVID_PANEL_FHD;
+	else if (attr == &dev_attr_cores_enabled.attr
+		|| attr == &dev_attr_cores_max.attr)
+		ok = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CORES_SET);
 	else if (attr == &dev_attr_mini_led_mode.attr)
 		ok = asus->mini_led_dev_id != 0;
 	else if (attr == &dev_attr_available_mini_led_mode.attr)
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 6c51d41ffc20..5a56e7e97785 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -116,6 +116,11 @@ 
 /* Charging mode - 1=Barrel, 2=USB */
 #define ASUS_WMI_DEVID_CHARGE_MODE	0x0012006C
 
+/* Intel E-core and P-core configuration in a format 0x0[E]0[P] */
+#define ASUS_WMI_DEVID_CORES_SET	0x001200D2
+ /* Maximum Intel E-core and P-core availability */
+#define ASUS_WMI_DEVID_CORES_MAX	0x001200D3
+
 /* MCU powersave mode */
 #define ASUS_WMI_DEVID_MCU_POWERSAVE   0x001200E2