Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package power-profiles-daemon for openSUSE:Factory checked in at 2023-04-28 16:22:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/power-profiles-daemon (Old) and /work/SRC/openSUSE:Factory/.power-profiles-daemon.new.1533 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "power-profiles-daemon" Fri Apr 28 16:22:25 2023 rev:7 rq:1083162 version:0.13 Changes: -------- --- /work/SRC/openSUSE:Factory/power-profiles-daemon/power-profiles-daemon.changes 2022-07-08 14:01:32.530422942 +0200 +++ /work/SRC/openSUSE:Factory/.power-profiles-daemon.new.1533/power-profiles-daemon.changes 2023-04-28 16:22:36.261742676 +0200 @@ -1,0 +2,9 @@ +Wed Apr 26 15:19:01 UTC 2023 - Enrico Belleri <ide...@protonmail.com> + +- Update to version 0.13: + * Add support for the AMD P-State driver included in Linux 6.3 + * Fix mismatched profiles on some HP laptops and some + miscellaneous bug fixes. + + +------------------------------------------------------------------- Old: ---- power-profiles-daemon-0.12.tar.bz2 New: ---- power-profiles-daemon-0.13.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ power-profiles-daemon.spec ++++++ --- /var/tmp/diff_new_pack.wzVs3f/_old 2023-04-28 16:22:37.461749680 +0200 +++ /var/tmp/diff_new_pack.wzVs3f/_new 2023-04-28 16:22:37.465749704 +0200 @@ -1,7 +1,7 @@ # # spec file for package power-profiles-daemon # -# Copyright (c) 2022 SUSE LLC +# Copyright (c) 2023 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: power-profiles-daemon -Version: 0.12 +Version: 0.13 Release: 0 Summary: Power profiles handling over D-Bus License: GPL-3.0-or-later @@ -28,16 +28,16 @@ BuildRequires: c_compiler BuildRequires: gtk-doc -BuildRequires: meson +BuildRequires: meson >= 0.54.0 BuildRequires: pkgconfig BuildRequires: python3-dbusmock BuildRequires: pkgconfig(gio-2.0) -BuildRequires: pkgconfig(gudev-1.0) +BuildRequires: pkgconfig(gudev-1.0) >= 234 BuildRequires: pkgconfig(polkit-gobject-1) >= 0.114 BuildRequires: pkgconfig(systemd) +BuildRequires: pkgconfig(upower-glib) BuildRequires: pkgconfig(udev) BuildRequires: pkgconfig(umockdev-1.0) -BuildRequires: pkgconfig(upower-glib) Requires: polkit %description @@ -59,6 +59,7 @@ %meson \ -Dsystemdsystemunitdir=%{_unitdir} \ -Dgtk_doc=true \ + -Dtests=true \ %{nil} %meson_build ++++++ power-profiles-daemon-0.12.tar.bz2 -> power-profiles-daemon-0.13.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/.gitlab-ci.yml new/power-profiles-daemon-0.13/.gitlab-ci.yml --- old/power-profiles-daemon-0.12/.gitlab-ci.yml 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/.gitlab-ci.yml 2023-04-26 14:53:07.000000000 +0200 @@ -18,6 +18,11 @@ umockdev e2fsprogs +workflow: + rules: + - if: $CI_PIPELINE_SOURCE == 'merge_request_event' + - if: $CI_PIPELINE_SOURCE == 'push' + build_stable: before_script: - dnf upgrade -y --nogpgcheck fedora-release fedora-repos* diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/NEWS new/power-profiles-daemon-0.13/NEWS --- old/power-profiles-daemon-0.12/NEWS 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/NEWS 2023-04-26 14:53:07.000000000 +0200 @@ -1,3 +1,10 @@ +0.13 +---- + +This release adds support for the AMD P-State driver that's been added to the +6.3 Linux kernel. This release also fixes mismatched profiles on some HP +laptops and some miscellaneous bug fixes. + 0.12 ---- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/README.md new/power-profiles-daemon-0.13/README.md --- old/power-profiles-daemon-0.12/README.md 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/README.md 2023-04-26 14:53:07.000000000 +0200 @@ -134,6 +134,35 @@ For more information, please refer to the [Intel P-State scaling driver documentation](https://www.kernel.org/doc/html/v5.17/admin-guide/pm/intel_pstate.html) and the [Intel Performance and Energy Bias Hint](https://www.kernel.org/doc/html/v5.17/admin-guide/pm/intel_epb.html). +Operations on AMD-based machines +---------------------------------- + +The "driver" for making the hardware act on the user-selected power profile on AMD CPU-based +machines is based on the [AMD P-State scaling driver](https://www.kernel.org/doc/html/v6.3/admin-guide/pm/amd-pstate.html) +if available. + +It is only used if a `platform_profile` driver isn't available for the system, the +CPU supports Collaborative Processor Performance Control (CPPC), and the AMD P-State +scaling driver is in `active` mode. + +Example of a system without `platform_profile` support but with `active` P-State +operation mode: +``` +$ cat /sys/firmware/acpi/platform_profile_choices +cat: /sys/firmware/acpi/platform_profile_choices: No such file or directory +$ cat /sys/devices/system/cpu/amd_pstate/status +active +``` + +If the AMD P-State scaling driver is not loaded or is not in `active` mode, then +the placeholder driver will be used, and there won't be a performance mode. + +Finally, if the AMD P-State scaling driver is used in `active` mode, the P-State +scaling governor will be changed to `powersave` as it is the only P-State scaling +governor that allows for the "Energy vs Performance Hints" to be taken into consideration. + +For more information, please refer to the [AMD P-State scaling driver documentation](https://www.kernel.org/doc/html/v6.3/admin-guide/pm/amd-pstate.html). + Testing ------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/docs/meson.build new/power-profiles-daemon-0.13/docs/meson.build --- old/power-profiles-daemon-0.12/docs/meson.build 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/docs/meson.build 2023-04-26 14:53:07.000000000 +0200 @@ -24,6 +24,7 @@ 'ppd-driver-balanced.h', 'ppd-driver-fake.h', 'ppd-driver-intel-pstate.h', + 'ppd-driver-amd-pstate.h', 'ppd-driver-placeholder.h', 'ppd-driver-platform-profile.h', 'ppd-driver-power-saver.h', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/meson.build new/power-profiles-daemon-0.13/meson.build --- old/power-profiles-daemon-0.12/meson.build 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/meson.build 2023-04-26 14:53:07.000000000 +0200 @@ -1,5 +1,5 @@ project('power-profiles-daemon', [ 'c' ], - version: '0.12', + version: '0.13', license: 'GPLv3+', default_options: [ 'buildtype=debugoptimized', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/meson.build new/power-profiles-daemon-0.13/src/meson.build --- old/power-profiles-daemon-0.12/src/meson.build 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/meson.build 2023-04-26 14:53:07.000000000 +0200 @@ -46,6 +46,7 @@ 'power-profiles-daemon.c', 'ppd-action-trickle-charge.c', 'ppd-driver-intel-pstate.c', + 'ppd-driver-amd-pstate.c', 'ppd-driver-platform-profile.c', 'ppd-driver-placeholder.c', 'ppd-driver-fake.c', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/power-profiles-daemon.c new/power-profiles-daemon-0.13/src/power-profiles-daemon.c --- old/power-profiles-daemon-0.12/src/power-profiles-daemon.c 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/power-profiles-daemon.c 2023-04-26 14:53:07.000000000 +0200 @@ -75,6 +75,7 @@ #include "ppd-driver-placeholder.h" #include "ppd-driver-platform-profile.h" #include "ppd-driver-intel-pstate.h" +#include "ppd-driver-amd-pstate.h" #include "ppd-driver-fake.h" typedef GType (*GTypeGetFunc) (void); @@ -84,6 +85,7 @@ ppd_driver_fake_get_type, ppd_driver_platform_profile_get_type, ppd_driver_intel_pstate_get_type, + ppd_driver_amd_pstate_get_type, /* Generic profile driver */ ppd_driver_placeholder_get_type, @@ -103,6 +105,16 @@ #define PROP_ALL (PROP_ACTIVE_PROFILE | PROP_INHIBITED | PROP_PROFILES | PROP_ACTIONS | PROP_DEGRADED | PROP_ACTIVE_PROFILE_HOLDS) +static gboolean +get_profile_available (PpdApp *data, + PpdProfile profile) +{ + PpdDriver *driver; + + driver = GET_DRIVER(profile); + return driver != NULL; +} + static const char * get_active_profile (PpdApp *data) { @@ -386,6 +398,11 @@ "Invalid profile name '%s'", profile); return FALSE; } + if (!get_profile_available (data, target_profile)) { + g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Cannot switch to unavailable profile '%s'", profile); + return FALSE; + } if (target_profile == data->active_profile) return TRUE; @@ -554,8 +571,14 @@ profile = ppd_profile_from_str (profile_name); if (profile != PPD_PROFILE_PERFORMANCE && profile != PPD_PROFILE_POWER_SAVER) { + g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Only profiles 'performance' and 'power-saver' can be a hold profile"); + return; + } + if (!get_profile_available (data, profile)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, - "Only profiles 'performance' and 'power-saver' can be a hold profile"); + "Cannot hold profile '%s' as it is not available", + profile_name); return; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/powerprofilesctl.in new/power-profiles-daemon-0.13/src/powerprofilesctl.in --- old/power-profiles-daemon-0.12/src/powerprofilesctl.in 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/powerprofilesctl.in 2023-04-26 14:53:07.000000000 +0200 @@ -127,44 +127,43 @@ profiles = proxy.Get('(ss)', 'net.hadess.PowerProfiles', prop) except: raise - else: - return profiles + return profiles def _list(): try: profiles = get_profiles_property('Profiles') reason = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'PerformanceDegraded') - degraded = (reason != '') + degraded = reason != '' active = get_proxy().Get('(ss)', 'net.hadess.PowerProfiles', 'ActiveProfile') except: raise - else: - index = 0 - for profile in reversed(profiles): - if index > 0: - print('') - marker = '*' if profile['Profile'] == active else ' ' - print(f'{marker} {profile["Profile"]}:') - print(' Driver: ', profile['Driver']) - if profile['Profile'] == 'performance': - print(' Degraded: ', f'yes ({reason})' if degraded else 'no') - index += 1 + + index = 0 + for profile in reversed(profiles): + if index > 0: + print('') + marker = '*' if profile['Profile'] == active else ' ' + print(f'{marker} {profile["Profile"]}:') + print(' Driver: ', profile['Driver']) + if profile['Profile'] == 'performance': + print(' Degraded: ', f'yes ({reason})' if degraded else 'no') + index += 1 def _list_holds(): try: holds = get_profiles_property('ActiveProfileHolds') except: raise - else: - index = 0 - for hold in holds: - if index > 0: - print('') - print('Hold:') - print(' Profile: ', hold['Profile']) - print(' Application ID: ', hold['ApplicationId']) - print(' Reason: ', hold['Reason']) - index += 1 + + index = 0 + for hold in holds: + if index > 0: + print('') + print('Hold:') + print(' Profile: ', hold['Profile']) + print(' Application ID: ', hold['ApplicationId']) + print(' Reason: ', hold['Reason']) + index += 1 def _launch(args, profile, appid, reason): try: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/ppd-driver-amd-pstate.c new/power-profiles-daemon-0.13/src/ppd-driver-amd-pstate.c --- old/power-profiles-daemon-0.12/src/ppd-driver-amd-pstate.c 1970-01-01 01:00:00.000000000 +0100 +++ new/power-profiles-daemon-0.13/src/ppd-driver-amd-pstate.c 2023-04-26 14:53:07.000000000 +0200 @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2020 Bastien Nocera <had...@hadess.net> + * Copyright (c) 2022 Prajna Sariputra <putr...@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + */ + +#include <upower.h> + +#include "ppd-utils.h" +#include "ppd-driver-amd-pstate.h" + +#define CPUFREQ_POLICY_DIR "/sys/devices/system/cpu/cpufreq/" +#define DEFAULT_CPU_FREQ_SCALING_GOV "powersave" +#define PSTATE_STATUS_PATH "/sys/devices/system/cpu/amd_pstate/status" + +struct _PpdDriverAmdPstate +{ + PpdDriver parent_instance; + + PpdProfile activated_profile; + GList *epp_devices; /* GList of paths */ +}; + +G_DEFINE_TYPE (PpdDriverAmdPstate, ppd_driver_amd_pstate, PPD_TYPE_DRIVER) + +static gboolean ppd_driver_amd_pstate_activate_profile (PpdDriver *driver, + PpdProfile profile, + PpdProfileActivationReason reason, + GError **error); + +static GObject* +ppd_driver_amd_pstate_constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) +{ + GObject *object; + + object = G_OBJECT_CLASS (ppd_driver_amd_pstate_parent_class)->constructor (type, + n_construct_params, + construct_params); + g_object_set (object, + "driver-name", "amd_pstate", + "profiles", PPD_PROFILE_PERFORMANCE | PPD_PROFILE_BALANCED | PPD_PROFILE_POWER_SAVER, + NULL); + + return object; +} + +static PpdProbeResult +probe_epp (PpdDriverAmdPstate *pstate) +{ + g_autoptr(GDir) dir = NULL; + g_autofree char *policy_dir = NULL; + g_autofree char *pstate_status_path = NULL; + g_autofree char *status = NULL; + const char *dirname; + PpdProbeResult ret = PPD_PROBE_RESULT_FAIL; + + /* Verify that AMD P-State is running in active mode */ + pstate_status_path = ppd_utils_get_sysfs_path (PSTATE_STATUS_PATH); + if (!g_file_get_contents (pstate_status_path, &status, NULL, NULL)) + return ret; + status = g_strchomp (status); + if (g_strcmp0 (status, "active") != 0) { + g_debug ("AMD P-State is not running in active mode"); + return ret; + } + + policy_dir = ppd_utils_get_sysfs_path (CPUFREQ_POLICY_DIR); + dir = g_dir_open (policy_dir, 0, NULL); + if (!dir) { + g_debug ("Could not open %s", policy_dir); + return ret; + } + + while ((dirname = g_dir_read_name (dir)) != NULL) { + g_autofree char *path = NULL; + g_autofree char *gov_path = NULL; + g_autoptr(GError) error = NULL; + + path = g_build_filename (policy_dir, + dirname, + "energy_performance_preference", + NULL); + if (!g_file_test (path, G_FILE_TEST_EXISTS)) + continue; + + /* Force a scaling_governor where the preference can be written */ + gov_path = g_build_filename (policy_dir, + dirname, + "scaling_governor", + NULL); + if (!ppd_utils_write (gov_path, DEFAULT_CPU_FREQ_SCALING_GOV, &error)) { + g_warning ("Could not change scaling governor %s to '%s'", dirname, DEFAULT_CPU_FREQ_SCALING_GOV); + continue; + } + + pstate->epp_devices = g_list_prepend (pstate->epp_devices, g_steal_pointer (&path)); + ret = PPD_PROBE_RESULT_SUCCESS; + } + + return ret; +} + +static PpdProbeResult +ppd_driver_amd_pstate_probe (PpdDriver *driver) +{ + PpdDriverAmdPstate *pstate = PPD_DRIVER_AMD_PSTATE (driver); + PpdProbeResult ret = PPD_PROBE_RESULT_FAIL; + + ret = probe_epp (pstate); + + if (ret != PPD_PROBE_RESULT_SUCCESS) + goto out; + +out: + g_debug ("%s p-state settings", + ret == PPD_PROBE_RESULT_SUCCESS ? "Found" : "Didn't find"); + return ret; +} + +static const char * +profile_to_epp_pref (PpdProfile profile) +{ + /* Note that we don't check "energy_performance_available_preferences" + * as all the values are always available */ + switch (profile) { + case PPD_PROFILE_POWER_SAVER: + return "power"; + case PPD_PROFILE_BALANCED: + return "balance_performance"; + case PPD_PROFILE_PERFORMANCE: + return "performance"; + } + + g_assert_not_reached (); +} + +static gboolean +apply_pref_to_devices (GList *devices, + const char *pref, + GError **error) +{ + gboolean ret = TRUE; + GList *l; + + for (l = devices; l != NULL; l = l->next) { + const char *path = l->data; + + ret = ppd_utils_write (path, pref, error); + if (!ret) + break; + } + + return ret; +} + +static gboolean +ppd_driver_amd_pstate_activate_profile (PpdDriver *driver, + PpdProfile profile, + PpdProfileActivationReason reason, + GError **error) +{ + PpdDriverAmdPstate *pstate = PPD_DRIVER_AMD_PSTATE (driver); + gboolean ret = FALSE; + const char *pref; + + g_return_val_if_fail (pstate->epp_devices != NULL, FALSE); + + if (pstate->epp_devices) { + pref = profile_to_epp_pref (profile); + ret = apply_pref_to_devices (pstate->epp_devices, pref, error); + if (!ret) + return ret; + } + + if (ret) + pstate->activated_profile = profile; + + return ret; +} + +static void +ppd_driver_amd_pstate_finalize (GObject *object) +{ + PpdDriverAmdPstate *driver; + + driver = PPD_DRIVER_AMD_PSTATE (object); + g_clear_list (&driver->epp_devices, g_free); + G_OBJECT_CLASS (ppd_driver_amd_pstate_parent_class)->finalize (object); +} + +static void +ppd_driver_amd_pstate_class_init (PpdDriverAmdPstateClass *klass) +{ + GObjectClass *object_class; + PpdDriverClass *driver_class; + + object_class = G_OBJECT_CLASS(klass); + object_class->constructor = ppd_driver_amd_pstate_constructor; + object_class->finalize = ppd_driver_amd_pstate_finalize; + + driver_class = PPD_DRIVER_CLASS(klass); + driver_class->probe = ppd_driver_amd_pstate_probe; + driver_class->activate_profile = ppd_driver_amd_pstate_activate_profile; +} + +static void +ppd_driver_amd_pstate_init (PpdDriverAmdPstate *self) +{ +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/ppd-driver-amd-pstate.h new/power-profiles-daemon-0.13/src/ppd-driver-amd-pstate.h --- old/power-profiles-daemon-0.12/src/ppd-driver-amd-pstate.h 1970-01-01 01:00:00.000000000 +0100 +++ new/power-profiles-daemon-0.13/src/ppd-driver-amd-pstate.h 2023-04-26 14:53:07.000000000 +0200 @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2020 Bastien Nocera <had...@hadess.net> + * Copyright (c) 2022 Prajna Sariputra <putr...@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published by + * the Free Software Foundation. + * + */ + +#pragma once + +#include "ppd-driver.h" + +#define PPD_TYPE_DRIVER_AMD_PSTATE (ppd_driver_amd_pstate_get_type()) +G_DECLARE_FINAL_TYPE(PpdDriverAmdPstate, ppd_driver_amd_pstate, PPD, DRIVER_AMD_PSTATE, PpdDriver) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/ppd-driver-intel-pstate.c new/power-profiles-daemon-0.13/src/ppd-driver-intel-pstate.c --- old/power-profiles-daemon-0.12/src/ppd-driver-intel-pstate.c 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/ppd-driver-intel-pstate.c 2023-04-26 14:53:07.000000000 +0200 @@ -171,7 +171,6 @@ while ((dirname = g_dir_read_name (dir)) != NULL) { g_autofree char *path = NULL; - g_autofree char *gov_path = NULL; path = g_build_filename (policy_dir, dirname, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/ppd-driver-platform-profile.c new/power-profiles-daemon-0.13/src/ppd-driver-platform-profile.c --- old/power-profiles-daemon-0.12/src/ppd-driver-platform-profile.c 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/ppd-driver-platform-profile.c 2023-04-26 14:53:07.000000000 +0200 @@ -26,6 +26,7 @@ int lapmode; PpdProfile acpi_platform_profile; char **profile_choices; + gboolean has_low_power; GFileMonitor *lapmode_mon; GFileMonitor *acpi_platform_profile_mon; guint acpi_platform_profile_changed_id; @@ -57,10 +58,10 @@ { switch (profile) { case PPD_PROFILE_POWER_SAVER: + if (!self->has_low_power) + return "balanced"; if (g_strv_contains ((const char * const*) self->profile_choices, "low-power")) return "low-power"; - if (g_strv_contains ((const char * const*) self->profile_choices, "cool")) - return "cool"; return "quiet"; case PPD_PROFILE_BALANCED: return "balanced"; @@ -79,9 +80,9 @@ switch (str[0]) { case 'l': /* low-power */ - case 'c': /* cool */ case 'q': /* quiet */ return PPD_PROFILE_POWER_SAVER; + case 'c': /* cool */ case 'b': return PPD_PROFILE_BALANCED; case 'p': @@ -142,12 +143,15 @@ { const char * const *choices = (const char * const*) self->profile_choices; - if ((g_strv_contains (choices, "low-power") || - g_strv_contains (choices, "cool") || - g_strv_contains (choices, "quiet")) && - g_strv_contains (choices, "balanced") && - g_strv_contains (choices, "performance")) + if (g_strv_contains (choices, "balanced") && + g_strv_contains (choices, "performance")) { + if (g_strv_contains (choices, "low-power") || + g_strv_contains (choices, "quiet")) + self->has_low_power = TRUE; + else + g_debug ("No \"low-power\" profile for device, will be emulated"); return PPD_PROBE_RESULT_SUCCESS; + } return PPD_PROBE_RESULT_DEFER; } @@ -203,7 +207,7 @@ gpointer user_data) { PpdDriverPlatformProfile *self = user_data; - g_debug (ACPI_PLATFORM_PROFILE_PATH " changed"); + g_debug (ACPI_PLATFORM_PROFILE_PATH " changed (%d)", event_type); if (self->probe_result == PPD_PROBE_RESULT_DEFER) { g_signal_emit_by_name (G_OBJECT (self), "probe-request", 0); return; @@ -219,6 +223,7 @@ { PpdDriverPlatformProfile *self = PPD_DRIVER_PLATFORM_PROFILE (driver); g_autofree char *platform_profile_path = NULL; + const char *platform_profile_value; g_return_val_if_fail (self->acpi_platform_profile_mon, FALSE); @@ -227,6 +232,14 @@ ppd_profile_to_str (profile)); return TRUE; } + + platform_profile_value = profile_to_acpi_platform_profile_value (self, profile); + if (self->acpi_platform_profile == acpi_platform_profile_value_to_profile (platform_profile_value)) { + g_debug ("Not switching to platform_profile %s, emulating for %s, already there", + platform_profile_value, + ppd_profile_to_str (profile)); + return TRUE; + } g_signal_handler_block (G_OBJECT (self->acpi_platform_profile_mon), self->acpi_platform_profile_changed_id); platform_profile_path = ppd_utils_get_sysfs_path (ACPI_PLATFORM_PROFILE_PATH); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/src/ppd-utils.c new/power-profiles-daemon-0.13/src/ppd-utils.c --- old/power-profiles-daemon-0.12/src/ppd-utils.c 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/src/ppd-utils.c 2023-04-26 14:53:07.000000000 +0200 @@ -85,6 +85,7 @@ path = g_build_filename (g_udev_device_get_sysfs_path (device), attribute, NULL); file = g_file_new_for_path (path); + g_debug ("Monitoring file %s for changes", path); return g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/power-profiles-daemon-0.12/tests/integration-test.py new/power-profiles-daemon-0.13/tests/integration-test.py --- old/power-profiles-daemon-0.12/tests/integration-test.py 2022-06-28 15:58:14.000000000 +0200 +++ new/power-profiles-daemon-0.13/tests/integration-test.py 2023-04-26 14:53:07.000000000 +0200 @@ -320,6 +320,13 @@ self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver')) self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver') + with self.assertRaises(gi.repository.GLib.GError): + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance')) + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver') + + with self.assertRaises(gi.repository.GLib.GError): + cookie = self.call_dbus_method('HoldProfile', GLib.Variant("(sss)", ('performance', 'testReason', 'testApplication'))) + # process = subprocess.Popen(['gdbus', 'introspect', '--system', '--dest', 'net.hadess.PowerProfiles', '--object-path', '/net/hadess/PowerProfiles']) # print (self.get_dbus_property('GPUs')) @@ -598,6 +605,183 @@ self.stop_daemon() + def test_amd_pstate(self): + '''AMD P-State driver (no UPower)''' + + # Create 2 CPUs with preferences + dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/") + os.makedirs(dir1) + with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov: + gov.write('powersave\n') + with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs: + prefs.write("performance\n") + dir2 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy1/") + os.makedirs(dir2) + with open(os.path.join(dir2, 'scaling_governor'), 'w') as gov: + gov.write('powersave\n') + with open(os.path.join(dir2, "energy_performance_preference"),'w') as prefs: + prefs.write("performance\n") + + # Create AMD P-State configuration + pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/amd_pstate") + os.makedirs(pstate_dir) + with open(os.path.join(pstate_dir, "status"),'w') as status: + status.write("active\n") + + self.start_daemon() + + profiles = self.get_dbus_property('Profiles') + self.assertEqual(len(profiles), 3) + self.assertEqual(profiles[0]['Driver'], 'amd_pstate') + self.assertEqual(profiles[0]['Profile'], 'power-saver') + + contents = None + with open(os.path.join(dir2, "energy_performance_preference"), 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'balance_performance') + + # Set performance mode + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance')) + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'performance') + + contents = None + with open(os.path.join(dir2, "energy_performance_preference"), 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'performance') + + self.stop_daemon() + + # Verify that the Lenovo DYTC driver still gets preferred + self.create_platform_profile() + self.start_daemon() + + profiles = self.get_dbus_property('Profiles') + self.assertEqual(len(profiles), 3) + self.assertEqual(profiles[0]['Driver'], 'platform_profile') + + def test_amd_pstate_balance(self): + '''AMD P-State driver (balance)''' + + # Create CPU with preference + dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/") + os.makedirs(dir1) + gov_path = os.path.join(dir1, 'scaling_governor') + with open(gov_path, 'w') as gov: + gov.write('performance\n') + with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs: + prefs.write("performance\n") + pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/amd_pstate") + os.makedirs(pstate_dir) + with open(os.path.join(pstate_dir, "status"),'w') as status: + status.write("active\n") + + upowerd, obj_upower = self.spawn_server_template( + 'upower', {'DaemonVersion': '0.99', 'OnBattery': False}, stdout=subprocess.PIPE) + + self.start_daemon() + + with open(gov_path, 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'powersave') + + profiles = self.get_dbus_property('Profiles') + self.assertEqual(len(profiles), 3) + self.assertEqual(profiles[0]['Driver'], 'amd_pstate') + self.assertEqual(profiles[0]['Profile'], 'power-saver') + + contents = None + with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f: + contents = f.read() + # This matches what's written by ppd-driver-amd-pstate.c + self.assertEqual(contents, b'balance_performance') + + self.stop_daemon() + + upowerd.terminate() + upowerd.wait() + upowerd.stdout.close() + + def test_amd_pstate_error(self): + '''AMD P-State driver in error state''' + + pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/amd_pstate") + os.makedirs(pstate_dir) + with open(os.path.join(pstate_dir, "status"),'w') as status: + status.write("active\n") + + dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/") + os.makedirs(dir1) + with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov: + gov.write('powersave\n') + pref_path = os.path.join(dir1, "energy_performance_preference") + old_umask = os.umask(0o333) + with open(pref_path,'w') as prefs: + prefs.write("balance_performance\n") + os.umask(old_umask) + # Make file non-writable to root + if os.geteuid() == 0: + if not GLib.find_program_in_path('chattr'): + os._exit(77) + subprocess.check_output(['chattr', '+i', pref_path]) + + self.start_daemon() + + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced') + + # Error when setting performance mode + with self.assertRaises(gi.repository.GLib.GError): + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance')) + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced') + + contents = None + with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'balance_performance\n') + + self.stop_daemon() + + if os.geteuid() == 0: + subprocess.check_output(['chattr', '-i', pref_path]) + + def test_amd_pstate_passive(self): + '''AMD P-State in passive mode -> placeholder''' + + dir1 = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/cpufreq/policy0/") + os.makedirs(dir1) + with open(os.path.join(dir1, 'scaling_governor'), 'w') as gov: + gov.write('powersave\n') + with open(os.path.join(dir1, "energy_performance_preference"),'w') as prefs: + prefs.write("performance\n") + + # Create AMD P-State configuration + pstate_dir = os.path.join(self.testbed.get_root_dir(), "sys/devices/system/cpu/amd_pstate") + os.makedirs(pstate_dir) + with open(os.path.join(pstate_dir, "status"),'w') as status: + status.write("passive\n") + + self.start_daemon() + + profiles = self.get_dbus_property('Profiles') + self.assertEqual(len(profiles), 2) + self.assertEqual(profiles[0]['Driver'], 'placeholder') + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced') + + contents = None + with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'performance\n') + + # Set performance mode + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver')) + self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver') + + contents = None + with open(os.path.join(dir1, "energy_performance_preference"), 'rb') as f: + contents = f.read() + self.assertEqual(contents, b'performance\n') + + self.stop_daemon() + def test_dytc_performance_driver(self): '''Lenovo DYTC performance driver''' @@ -753,19 +937,23 @@ self.assertEqual(profiles[0]['Driver'], 'platform_profile') self.assertEqual(profiles[0]['Profile'], 'power-saver') self.assertEqual(self.get_dbus_property('ActiveProfile'), 'balanced') - self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'balanced') + self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'cool') self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('power-saver')) self.assertEqual(self.get_dbus_property('ActiveProfile'), 'power-saver') self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'cool') + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('performance')) + self.set_dbus_property('ActiveProfile', GLib.Variant.new_string('balanced')) + self.assertEqual(self.read_sysfs_file("sys/firmware/acpi/platform_profile"), b'balanced') + self.stop_daemon() def test_quiet(self): - # Uses cool instead of low-power + # Uses quiet instead of low-power acpi_dir = os.path.join(self.testbed.get_root_dir(), "sys/firmware/acpi/") os.makedirs(acpi_dir) with open(os.path.join(acpi_dir, "platform_profile"),'w') as profile: - profile.write("cool\n") + profile.write("quiet\n") with open(os.path.join(acpi_dir, "platform_profile_choices"),'w') as choices: choices.write("quiet balanced balanced-performance performance\n")