As multiple platform profile handlers might not all support the same
profile, cycling to the next profile could have a different result
depending on what handler are registered.
Check what is active and supported by all handlers to decide what
to do.
Tested-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
drivers/acpi/platform_profile.c | 52 +++++++++++++++++----------------
1 file changed, 27 insertions(+), 25 deletions(-)
diff --git a/drivers/acpi/platform_profile.c b/drivers/acpi/platform_profile.c
index d22c4eb5f0c36..e6ea5b600e2af 100644
--- a/drivers/acpi/platform_profile.c
+++ b/drivers/acpi/platform_profile.c
@@ -196,40 +196,42 @@ EXPORT_SYMBOL_GPL(platform_profile_notify);
int platform_profile_cycle(void)
{
+ enum platform_profile_option next = PLATFORM_PROFILE_LAST;
+ struct platform_profile_handler *handler;
enum platform_profile_option profile;
- enum platform_profile_option next;
+ unsigned long choices;
int err;
- err = mutex_lock_interruptible(&profile_lock);
- if (err)
- return err;
-
- if (!cur_profile) {
- mutex_unlock(&profile_lock);
- return -ENODEV;
- }
+ scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) {
+ err = platform_profile_get_active(&profile);
+ if (err)
+ return err;
- err = cur_profile->profile_get(cur_profile, &profile);
- if (err) {
- mutex_unlock(&profile_lock);
- return err;
- }
+ choices = platform_profile_get_choices();
- next = find_next_bit_wrap(cur_profile->choices, PLATFORM_PROFILE_LAST,
- profile + 1);
+ next = find_next_bit_wrap(&choices,
+ PLATFORM_PROFILE_LAST,
+ profile + 1);
- if (WARN_ON(next == PLATFORM_PROFILE_LAST)) {
- mutex_unlock(&profile_lock);
- return -EINVAL;
+ list_for_each_entry(handler, &platform_profile_handler_list, list) {
+ err = handler->profile_set(handler, next);
+ if (err) {
+ pr_err("Failed to set profile for handler %s\n", handler->name);
+ break;
+ }
+ }
+ if (err) {
+ list_for_each_entry_continue_reverse(handler, &platform_profile_handler_list, list) {
+ err = handler->profile_set(handler, PLATFORM_PROFILE_BALANCED);
+ if (err)
+ pr_err("Failed to revert profile for handler %s\n", handler->name);
+ }
+ }
}
- err = cur_profile->profile_set(cur_profile, next);
- mutex_unlock(&profile_lock);
-
- if (!err)
- sysfs_notify(acpi_kobj, NULL, "platform_profile");
+ sysfs_notify(acpi_kobj, NULL, "platform_profile");
- return err;
+ return 0;
}
EXPORT_SYMBOL_GPL(platform_profile_cycle);
--
2.43.0