-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'linux-pm/acpi-platform' into review-hans
- Loading branch information
Showing
7 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
What: /sys/firmware/acpi/platform_profile_choices | ||
Date: October 2020 | ||
Contact: Hans de Goede <hdegoede@redhat.com> | ||
Description: This file contains a space-separated list of profiles supported for this device. | ||
|
||
Drivers must use the following standard profile-names: | ||
|
||
============ ============================================ | ||
low-power Low power consumption | ||
cool Cooler operation | ||
quiet Quieter operation | ||
balanced Balance between low power consumption and performance | ||
performance High performance operation | ||
============ ============================================ | ||
|
||
Userspace may expect drivers to offer more than one of these | ||
standard profile names. | ||
|
||
What: /sys/firmware/acpi/platform_profile | ||
Date: October 2020 | ||
Contact: Hans de Goede <hdegoede@redhat.com> | ||
Description: Reading this file gives the current selected profile for this | ||
device. Writing this file with one of the strings from | ||
platform_profile_choices changes the profile to the new value. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
===================================================================== | ||
Platform Profile Selection (e.g. /sys/firmware/acpi/platform_profile) | ||
===================================================================== | ||
|
||
On modern systems the platform performance, temperature, fan and other | ||
hardware related characteristics are often dynamically configurable. The | ||
platform configuration is often automatically adjusted to the current | ||
conditions by some automatic mechanism (which may very well live outside | ||
the kernel). | ||
|
||
These auto platform adjustment mechanisms often can be configured with | ||
one of several platform profiles, with either a bias towards low power | ||
operation or towards performance. | ||
|
||
The purpose of the platform_profile attribute is to offer a generic sysfs | ||
API for selecting the platform profile of these automatic mechanisms. | ||
|
||
Note that this API is only for selecting the platform profile, it is | ||
NOT a goal of this API to allow monitoring the resulting performance | ||
characteristics. Monitoring performance is best done with device/vendor | ||
specific tools such as e.g. turbostat. | ||
|
||
Specifically when selecting a high performance profile the actual achieved | ||
performance may be limited by various factors such as: the heat generated | ||
by other components, room temperature, free air flow at the bottom of a | ||
laptop, etc. It is explicitly NOT a goal of this API to let userspace know | ||
about any sub-optimal conditions which are impeding reaching the requested | ||
performance level. | ||
|
||
Since numbers on their own cannot represent the multiple variables that a | ||
profile will adjust (power consumption, heat generation, etc) this API | ||
uses strings to describe the various profiles. To make sure that userspace | ||
gets a consistent experience the sysfs-platform_profile ABI document defines | ||
a fixed set of profile names. Drivers *must* map their internal profile | ||
representation onto this fixed set. | ||
|
||
If there is no good match when mapping then a new profile name may be | ||
added. Drivers which wish to introduce new profile names must: | ||
|
||
1. Explain why the existing profile names canot be used. | ||
2. Add the new profile name, along with a clear description of the | ||
expected behaviour, to the sysfs-platform_profile ABI documentation. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
|
||
/* Platform profile sysfs interface */ | ||
|
||
#include <linux/acpi.h> | ||
#include <linux/bits.h> | ||
#include <linux/init.h> | ||
#include <linux/mutex.h> | ||
#include <linux/platform_profile.h> | ||
#include <linux/sysfs.h> | ||
|
||
static struct platform_profile_handler *cur_profile; | ||
static DEFINE_MUTEX(profile_lock); | ||
|
||
static const char * const profile_names[] = { | ||
[PLATFORM_PROFILE_LOW_POWER] = "low-power", | ||
[PLATFORM_PROFILE_COOL] = "cool", | ||
[PLATFORM_PROFILE_QUIET] = "quiet", | ||
[PLATFORM_PROFILE_BALANCED] = "balanced", | ||
[PLATFORM_PROFILE_PERFORMANCE] = "performance", | ||
}; | ||
static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST); | ||
|
||
static ssize_t platform_profile_choices_show(struct device *dev, | ||
struct device_attribute *attr, | ||
char *buf) | ||
{ | ||
int len = 0; | ||
int err, i; | ||
|
||
err = mutex_lock_interruptible(&profile_lock); | ||
if (err) | ||
return err; | ||
|
||
if (!cur_profile) { | ||
mutex_unlock(&profile_lock); | ||
return -ENODEV; | ||
} | ||
|
||
for_each_set_bit(i, cur_profile->choices, PLATFORM_PROFILE_LAST) { | ||
if (len == 0) | ||
len += sysfs_emit_at(buf, len, "%s", profile_names[i]); | ||
else | ||
len += sysfs_emit_at(buf, len, " %s", profile_names[i]); | ||
} | ||
len += sysfs_emit_at(buf, len, "\n"); | ||
mutex_unlock(&profile_lock); | ||
return len; | ||
} | ||
|
||
static ssize_t platform_profile_show(struct device *dev, | ||
struct device_attribute *attr, | ||
char *buf) | ||
{ | ||
enum platform_profile_option profile = PLATFORM_PROFILE_BALANCED; | ||
int err; | ||
|
||
err = mutex_lock_interruptible(&profile_lock); | ||
if (err) | ||
return err; | ||
|
||
if (!cur_profile) { | ||
mutex_unlock(&profile_lock); | ||
return -ENODEV; | ||
} | ||
|
||
err = cur_profile->profile_get(cur_profile, &profile); | ||
mutex_unlock(&profile_lock); | ||
if (err) | ||
return err; | ||
|
||
/* Check that profile is valid index */ | ||
if (WARN_ON((profile < 0) || (profile >= ARRAY_SIZE(profile_names)))) | ||
return -EIO; | ||
|
||
return sysfs_emit(buf, "%s\n", profile_names[profile]); | ||
} | ||
|
||
static ssize_t platform_profile_store(struct device *dev, | ||
struct device_attribute *attr, | ||
const char *buf, size_t count) | ||
{ | ||
int err, i; | ||
|
||
err = mutex_lock_interruptible(&profile_lock); | ||
if (err) | ||
return err; | ||
|
||
if (!cur_profile) { | ||
mutex_unlock(&profile_lock); | ||
return -ENODEV; | ||
} | ||
|
||
/* Scan for a matching profile */ | ||
i = sysfs_match_string(profile_names, buf); | ||
if (i < 0) { | ||
mutex_unlock(&profile_lock); | ||
return -EINVAL; | ||
} | ||
|
||
/* Check that platform supports this profile choice */ | ||
if (!test_bit(i, cur_profile->choices)) { | ||
mutex_unlock(&profile_lock); | ||
return -EOPNOTSUPP; | ||
} | ||
|
||
err = cur_profile->profile_set(cur_profile, i); | ||
mutex_unlock(&profile_lock); | ||
if (err) | ||
return err; | ||
return count; | ||
} | ||
|
||
static DEVICE_ATTR_RO(platform_profile_choices); | ||
static DEVICE_ATTR_RW(platform_profile); | ||
|
||
static struct attribute *platform_profile_attrs[] = { | ||
&dev_attr_platform_profile_choices.attr, | ||
&dev_attr_platform_profile.attr, | ||
NULL | ||
}; | ||
|
||
static const struct attribute_group platform_profile_group = { | ||
.attrs = platform_profile_attrs | ||
}; | ||
|
||
void platform_profile_notify(void) | ||
{ | ||
if (!cur_profile) | ||
return; | ||
sysfs_notify(acpi_kobj, NULL, "platform_profile"); | ||
} | ||
EXPORT_SYMBOL_GPL(platform_profile_notify); | ||
|
||
int platform_profile_register(struct platform_profile_handler *pprof) | ||
{ | ||
int err; | ||
|
||
mutex_lock(&profile_lock); | ||
/* We can only have one active profile */ | ||
if (cur_profile) { | ||
mutex_unlock(&profile_lock); | ||
return -EEXIST; | ||
} | ||
|
||
/* Sanity check the profile handler field are set */ | ||
if (!pprof || bitmap_empty(pprof->choices, PLATFORM_PROFILE_LAST) || | ||
!pprof->profile_set || !pprof->profile_get) { | ||
mutex_unlock(&profile_lock); | ||
return -EINVAL; | ||
} | ||
|
||
err = sysfs_create_group(acpi_kobj, &platform_profile_group); | ||
if (err) { | ||
mutex_unlock(&profile_lock); | ||
return err; | ||
} | ||
|
||
cur_profile = pprof; | ||
mutex_unlock(&profile_lock); | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(platform_profile_register); | ||
|
||
int platform_profile_remove(void) | ||
{ | ||
sysfs_remove_group(acpi_kobj, &platform_profile_group); | ||
|
||
mutex_lock(&profile_lock); | ||
cur_profile = NULL; | ||
mutex_unlock(&profile_lock); | ||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(platform_profile_remove); | ||
|
||
MODULE_AUTHOR("Mark Pearson <markpearson@lenovo.com>"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
/* | ||
* Platform profile sysfs interface | ||
* | ||
* See Documentation/ABI/testing/sysfs-platform_profile.rst for more | ||
* information. | ||
*/ | ||
|
||
#ifndef _PLATFORM_PROFILE_H_ | ||
#define _PLATFORM_PROFILE_H_ | ||
|
||
#include <linux/bitops.h> | ||
|
||
/* | ||
* If more options are added please update profile_names | ||
* array in platform-profile.c and sysfs-platform-profile.rst | ||
* documentation. | ||
*/ | ||
|
||
enum platform_profile_option { | ||
PLATFORM_PROFILE_LOW_POWER, | ||
PLATFORM_PROFILE_COOL, | ||
PLATFORM_PROFILE_QUIET, | ||
PLATFORM_PROFILE_BALANCED, | ||
PLATFORM_PROFILE_PERFORMANCE, | ||
PLATFORM_PROFILE_LAST, /*must always be last */ | ||
}; | ||
|
||
struct platform_profile_handler { | ||
unsigned long choices[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)]; | ||
int (*profile_get)(struct platform_profile_handler *pprof, | ||
enum platform_profile_option *profile); | ||
int (*profile_set)(struct platform_profile_handler *pprof, | ||
enum platform_profile_option profile); | ||
}; | ||
|
||
int platform_profile_register(struct platform_profile_handler *pprof); | ||
int platform_profile_remove(void); | ||
void platform_profile_notify(void); | ||
|
||
#endif /*_PLATFORM_PROFILE_H_*/ |