Fix the handling of of the kernel change from "quiet" to "low-power"

A coming kernel change will convert "quiet" to "low-power" due to how
platform_profile can now have multiple registered handlers.
(kernel 6.14 est)

Fixes #609
This commit is contained in:
Luke Jones
2025-02-14 19:38:02 +13:00
parent 2c006699f2
commit 4dd29952c8
13 changed files with 146 additions and 71 deletions

View File

@@ -927,16 +927,16 @@ fn handle_throttle_profile(
let proxy = PlatformProxyBlocking::new(conn)?; let proxy = PlatformProxyBlocking::new(conn)?;
let current = proxy.platform_profile()?; let current = proxy.platform_profile()?;
let choices = proxy.platform_profile_choices()?;
if cmd.next { if cmd.next {
proxy.set_platform_profile(current.next())?; proxy.set_platform_profile(PlatformProfile::next(current, &choices))?;
} else if let Some(profile) = cmd.profile_set { } else if let Some(profile) = cmd.profile_set {
proxy.set_platform_profile(profile)?; proxy.set_platform_profile(profile)?;
} }
if cmd.list { if cmd.list {
let res = PlatformProfile::list(); for p in &choices {
for p in &res {
println!("{:?}", p); println!("{:?}", p);
} }
} }

View File

@@ -216,7 +216,7 @@ impl CtrlFanCurveZbus {
.lock() .lock()
.await .await
.profiles .profiles
.set_active_curve_to_defaults((&active).into(), &mut find_fan_curve_node()?)?; .set_active_curve_to_defaults(active.as_str().into(), &mut find_fan_curve_node()?)?;
self.platform.set_platform_profile(active.as_str())?; self.platform.set_platform_profile(active.as_str())?;
self.config.lock().await.write(); self.config.lock().await.write();

View File

@@ -211,6 +211,7 @@ impl CtrlPlatform {
PlatformProfile::Balanced => self.config.lock().await.profile_balanced_epp, PlatformProfile::Balanced => self.config.lock().await.profile_balanced_epp,
PlatformProfile::Performance => self.config.lock().await.profile_performance_epp, PlatformProfile::Performance => self.config.lock().await.profile_performance_epp,
PlatformProfile::Quiet => self.config.lock().await.profile_quiet_epp, PlatformProfile::Quiet => self.config.lock().await.profile_quiet_epp,
PlatformProfile::LowPower => self.config.lock().await.profile_quiet_epp,
} }
} }
@@ -323,7 +324,9 @@ impl CtrlPlatform {
) -> Result<(), FdoErr> { ) -> Result<(), FdoErr> {
let policy: PlatformProfile = let policy: PlatformProfile =
platform_get_value!(self, platform_profile, "platform_profile").map(|n| n.into())?; platform_get_value!(self, platform_profile, "platform_profile").map(|n| n.into())?;
let policy = PlatformProfile::next(policy); let choices =
platform_get_value!(self, platform_profile_choices, "platform_profile_choices")?;
let policy = PlatformProfile::next(policy, &choices);
if self.platform.has_platform_profile() { if self.platform.has_platform_profile() {
let change_epp = self.config.lock().await.platform_profile_linked_epp; let change_epp = self.config.lock().await.platform_profile_linked_epp;
@@ -344,9 +347,24 @@ impl CtrlPlatform {
} }
} }
#[zbus(property)]
fn platform_profile_choices(&self) -> Result<Vec<PlatformProfile>, FdoErr> {
platform_get_value!(self, platform_profile_choices, "platform_profile_choices")
}
#[zbus(property)] #[zbus(property)]
fn platform_profile(&self) -> Result<PlatformProfile, FdoErr> { fn platform_profile(&self) -> Result<PlatformProfile, FdoErr> {
platform_get_value!(self, platform_profile, "platform_profile").map(|n| n.into()) let choices = self.platform.get_platform_profile_choices()?;
let policy: PlatformProfile = self.platform.get_platform_profile()?.as_str().into();
let policy = if policy == PlatformProfile::LowPower
&& choices.contains(&PlatformProfile::LowPower)
{
PlatformProfile::Quiet
} else {
policy
};
Ok(policy)
} }
#[zbus(property)] #[zbus(property)]
@@ -362,7 +380,16 @@ impl CtrlPlatform {
self.check_and_set_epp(epp, change_epp); self.check_and_set_epp(epp, change_epp);
self.config.lock().await.write(); self.config.lock().await.write();
// TODO: Need to get supported profiles here and ensure we translate to one
let choices = self.platform.get_platform_profile_choices()?;
let policy = if policy == PlatformProfile::Quiet
&& choices.contains(&PlatformProfile::LowPower)
{
PlatformProfile::LowPower
} else {
policy
};
self.platform self.platform
.set_platform_profile(policy.into()) .set_platform_profile(policy.into())
.map_err(|err| { .map_err(|err| {
@@ -623,6 +650,7 @@ impl ReloadAndNotify for CtrlPlatform {
PlatformProfile::Balanced => data.profile_balanced_epp, PlatformProfile::Balanced => data.profile_balanced_epp,
PlatformProfile::Performance => data.profile_performance_epp, PlatformProfile::Performance => data.profile_performance_epp,
PlatformProfile::Quiet => data.profile_quiet_epp, PlatformProfile::Quiet => data.profile_quiet_epp,
PlatformProfile::LowPower => data.profile_quiet_epp,
}; };
warn!("setting epp to {epp:?}"); warn!("setting epp to {epp:?}");
self.check_and_set_epp(epp, true); self.check_and_set_epp(epp, true);

View File

@@ -35,8 +35,10 @@ async fn main() -> Result<()> {
// If we're running under gamescope we have to set WAYLAND_DISPLAY for winit to // If we're running under gamescope we have to set WAYLAND_DISPLAY for winit to
// use // use
if let Ok(gamescope) = env::var("GAMESCOPE_WAYLAND_DISPLAY") { if let Ok(gamescope) = env::var("GAMESCOPE_WAYLAND_DISPLAY") {
if !gamescope.is_empty() {
env::set_var("WAYLAND_DISPLAY", gamescope); env::set_var("WAYLAND_DISPLAY", gamescope);
} }
}
// Try to open a proxy and check for app state first // Try to open a proxy and check for app state first
{ {

View File

@@ -9,6 +9,7 @@ impl From<Profile> for PlatformProfile {
Profile::Balanced => PlatformProfile::Balanced, Profile::Balanced => PlatformProfile::Balanced,
Profile::Performance => PlatformProfile::Performance, Profile::Performance => PlatformProfile::Performance,
Profile::Quiet => PlatformProfile::Quiet, Profile::Quiet => PlatformProfile::Quiet,
Profile::LowPower => PlatformProfile::LowPower,
} }
} }
} }
@@ -19,6 +20,7 @@ impl From<PlatformProfile> for Profile {
PlatformProfile::Balanced => Profile::Balanced, PlatformProfile::Balanced => Profile::Balanced,
PlatformProfile::Performance => Profile::Performance, PlatformProfile::Performance => Profile::Performance,
PlatformProfile::Quiet => Profile::Quiet, PlatformProfile::Quiet => Profile::Quiet,
PlatformProfile::LowPower => Profile::LowPower,
} }
} }
} }

View File

@@ -2,7 +2,7 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2025-02-14 03:05+0000\n" "POT-Creation-Date: 2025-02-14 06:37+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -27,6 +27,11 @@ msgctxt "SystemPageData"
msgid "Quiet" msgid "Quiet"
msgstr "" msgstr ""
#: rog-control-center/ui/pages/system.slint:20
msgctxt "SystemPageData"
msgid "LowPower"
msgstr ""
#: rog-control-center/ui/pages/system.slint:23 #: rog-control-center/ui/pages/system.slint:23
msgctxt "SystemPageData" msgctxt "SystemPageData"
msgid "Default" msgid "Default"

View File

@@ -4,6 +4,7 @@ export enum Profile {
Balanced, Balanced,
Performance, Performance,
Quiet, Quiet,
LowPower,
} }
export enum FanType { export enum FanType {

View File

@@ -99,6 +99,10 @@ pub trait Platform {
#[zbus(property)] #[zbus(property)]
fn set_profile_quiet_epp(&self, epp: CPUEPP) -> zbus::Result<()>; fn set_profile_quiet_epp(&self, epp: CPUEPP) -> zbus::Result<()>;
/// PlatformProfileChoices property
#[zbus(property)]
fn platform_profile_choices(&self) -> zbus::Result<Vec<PlatformProfile>>;
/// ThrottlePolicy property /// ThrottlePolicy property
#[zbus(property)] #[zbus(property)]
fn platform_profile(&self) -> zbus::Result<PlatformProfile>; fn platform_profile(&self) -> zbus::Result<PlatformProfile>;

View File

@@ -207,6 +207,7 @@ impl From<PlatformProfile> for CPUEPP {
PlatformProfile::Balanced => CPUEPP::BalancePerformance, PlatformProfile::Balanced => CPUEPP::BalancePerformance,
PlatformProfile::Performance => CPUEPP::Performance, PlatformProfile::Performance => CPUEPP::Performance,
PlatformProfile::Quiet => CPUEPP::Power, PlatformProfile::Quiet => CPUEPP::Power,
PlatformProfile::LowPower => CPUEPP::Power,
} }
} }
} }

View File

@@ -15,6 +15,7 @@ use std::path::Path;
use error::{PlatformError, Result}; use error::{PlatformError, Result};
use log::warn; use log::warn;
use platform::PlatformProfile;
use udev::Device; use udev::Device;
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");
@@ -107,6 +108,18 @@ pub fn write_attr_string(device: &mut Device, attr: &str, value: &str) -> Result
.map_err(|e| PlatformError::IoPath(attr.into(), e)) .map_err(|e| PlatformError::IoPath(attr.into(), e))
} }
pub fn read_attr_string_array(device: &Device, attr_name: &str) -> Result<Vec<PlatformProfile>> {
if let Some(value) = device.attribute_value(attr_name) {
let tmp: Vec<PlatformProfile> = value
.to_string_lossy()
.split(' ')
.map(PlatformProfile::from)
.collect();
return Ok(tmp);
}
Err(PlatformError::AttrNotFound(attr_name.to_owned()))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]

View File

@@ -154,6 +154,18 @@ macro_rules! get_attr_string {
}; };
} }
#[macro_export]
macro_rules! get_attr_string_array {
($(#[$attr:meta])* $attr_name:literal $item:ident) => {
concat_idents::concat_idents!(fn_name = get_, $attr_name {
$(#[$attr])*
pub fn fn_name(&self) -> Result<Vec<PlatformProfile>> {
$crate::read_attr_string_array(&to_device(&self.$item)?, $attr_name)
}
});
};
}
#[macro_export] #[macro_export]
macro_rules! set_attr_string { macro_rules! set_attr_string {
($(#[$attr:meta])* $attr_name:literal $item:ident) => { ($(#[$attr:meta])* $attr_name:literal $item:ident) => {
@@ -175,3 +187,12 @@ macro_rules! attr_string {
$crate::watch_attr!($attr_name $item); $crate::watch_attr!($attr_name $item);
}; };
} }
#[macro_export]
macro_rules! attr_string_array {
($(#[$attr:meta])* $attr_name:literal, $item:ident) => {
$crate::has_attr!($attr_name $item);
$crate::get_attr_string_array!($attr_name $item);
$crate::watch_attr!($attr_name $item);
};
}

View File

@@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use zbus::zvariant::{OwnedValue, Type, Value}; use zbus::zvariant::{OwnedValue, Type, Value};
use crate::error::{PlatformError, Result}; use crate::error::{PlatformError, Result};
use crate::{attr_string, to_device}; use crate::{attr_string, attr_string_array, to_device};
/// The "platform" device provides access to things like: /// The "platform" device provides access to things like:
/// - `dgpu_disable` /// - `dgpu_disable`
@@ -30,6 +30,12 @@ impl RogPlatform {
pp_path pp_path
); );
attr_string_array!(
/// The acpi platform_profile support
"platform_profile_choices",
pp_path
);
pub fn new() -> Result<Self> { pub fn new() -> Result<Self> {
let mut enumerator = udev::Enumerator::new().map_err(|err| { let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err); warn!("{}", err);
@@ -169,7 +175,7 @@ impl Display for GpuMode {
} }
} }
#[repr(u32)] #[repr(i32)]
#[derive( #[derive(
Deserialize, Deserialize,
Serialize, Serialize,
@@ -185,39 +191,40 @@ impl Display for GpuMode {
Clone, Clone,
Copy, Copy,
)] )]
#[zvariant(signature = "u")] #[zvariant(signature = "i")]
/// `platform_profile` in asus_wmi /// `platform_profile` in asus_wmi
pub enum PlatformProfile { pub enum PlatformProfile {
#[default] #[default]
Balanced = 0, Balanced = 0,
Performance = 1, Performance = 1,
Quiet = 2, Quiet = 2,
LowPower = 3,
} }
impl PlatformProfile { impl PlatformProfile {
pub const fn next(self) -> Self { pub fn next(current: Self, choices: &[Self]) -> Self {
match self { match current {
Self::Balanced => Self::Performance, Self::Balanced => Self::Performance,
Self::Performance => Self::Quiet, Self::Performance => {
if choices.contains(&Self::LowPower) {
Self::LowPower
} else {
Self::Quiet
}
}
Self::Quiet => Self::Balanced, Self::Quiet => Self::Balanced,
Self::LowPower => Self::Balanced,
} }
} }
pub const fn list() -> [Self; 3] {
[
Self::Balanced,
Self::Performance,
Self::Quiet,
]
}
} }
impl From<u8> for PlatformProfile { impl From<i32> for PlatformProfile {
fn from(num: u8) -> Self { fn from(num: i32) -> Self {
match num { match num {
0 => Self::Balanced, 0 => Self::Balanced,
1 => Self::Performance, 1 => Self::Performance,
2 => Self::Quiet, 2 => Self::Quiet,
3 => Self::LowPower,
_ => { _ => {
warn!("Unknown number for PlatformProfile: {}", num); warn!("Unknown number for PlatformProfile: {}", num);
Self::Balanced Self::Balanced
@@ -226,56 +233,38 @@ impl From<u8> for PlatformProfile {
} }
} }
impl From<i32> for PlatformProfile {
fn from(num: i32) -> Self {
(num as u8).into()
}
}
impl From<PlatformProfile> for u8 {
fn from(p: PlatformProfile) -> Self {
match p {
PlatformProfile::Balanced => 0,
PlatformProfile::Performance => 1,
PlatformProfile::Quiet => 2,
}
}
}
impl From<PlatformProfile> for i32 { impl From<PlatformProfile> for i32 {
fn from(p: PlatformProfile) -> Self { fn from(p: PlatformProfile) -> Self {
<u8>::from(p) as i32 p as i32
}
}
impl From<&PlatformProfile> for &str {
fn from(profile: &PlatformProfile) -> &'static str {
match profile {
PlatformProfile::Balanced => "balanced",
PlatformProfile::Performance => "performance",
PlatformProfile::Quiet => "quiet",
PlatformProfile::LowPower => "low-power",
}
} }
} }
impl From<PlatformProfile> for &str { impl From<PlatformProfile> for &str {
fn from(profile: PlatformProfile) -> &'static str { fn from(profile: PlatformProfile) -> &'static str {
match profile { <&str>::from(&profile)
PlatformProfile::Balanced => "balanced",
PlatformProfile::Performance => "performance",
PlatformProfile::Quiet => "quiet",
}
} }
} }
impl From<String> for PlatformProfile { impl From<String> for PlatformProfile {
fn from(profile: String) -> Self { fn from(profile: String) -> Self {
Self::from(&profile) Self::from(profile.as_str())
} }
} }
impl From<&String> for PlatformProfile { impl Display for PlatformProfile {
fn from(profile: &String) -> Self { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match profile.to_ascii_lowercase().trim() { write!(f, "({})", <&str>::from(self))
"balanced" => PlatformProfile::Balanced,
"performance" => PlatformProfile::Performance,
"quiet" => PlatformProfile::Quiet,
"low-power" => PlatformProfile::Quiet,
_ => {
warn!("{profile} is unknown, using ThrottlePolicy::Balanced");
PlatformProfile::Balanced
}
}
} }
} }
@@ -287,15 +276,24 @@ impl std::str::FromStr for PlatformProfile {
"balanced" => Ok(PlatformProfile::Balanced), "balanced" => Ok(PlatformProfile::Balanced),
"performance" => Ok(PlatformProfile::Performance), "performance" => Ok(PlatformProfile::Performance),
"quiet" => Ok(PlatformProfile::Quiet), "quiet" => Ok(PlatformProfile::Quiet),
"low-power" => Ok(PlatformProfile::Quiet), "low-power" => Ok(PlatformProfile::LowPower),
_ => Err(PlatformError::NotSupported), _ => Err(PlatformError::NotSupported),
} }
} }
} }
impl Display for PlatformProfile { impl From<&str> for PlatformProfile {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn from(profile: &str) -> Self {
write!(f, "{:?}", self) match profile.to_ascii_lowercase().trim() {
"balanced" => PlatformProfile::Balanced,
"performance" => PlatformProfile::Performance,
"quiet" => PlatformProfile::Quiet,
"low-power" => PlatformProfile::LowPower,
_ => {
warn!("{profile} is unknown, using ThrottlePolicy::Balanced");
PlatformProfile::Balanced
}
}
} }
} }

View File

@@ -145,7 +145,7 @@ impl FanCurveProfiles {
match profile { match profile {
PlatformProfile::Balanced => self.balanced = curves, PlatformProfile::Balanced => self.balanced = curves,
PlatformProfile::Performance => self.performance = curves, PlatformProfile::Performance => self.performance = curves,
PlatformProfile::Quiet => self.quiet = curves, PlatformProfile::Quiet | PlatformProfile::LowPower => self.quiet = curves,
} }
Ok(()) Ok(())
} }
@@ -181,7 +181,7 @@ impl FanCurveProfiles {
let fans = match profile { let fans = match profile {
PlatformProfile::Balanced => &mut self.balanced, PlatformProfile::Balanced => &mut self.balanced,
PlatformProfile::Performance => &mut self.performance, PlatformProfile::Performance => &mut self.performance,
PlatformProfile::Quiet => &mut self.quiet, PlatformProfile::Quiet | PlatformProfile::LowPower => &mut self.quiet,
}; };
for fan in fans.iter().filter(|f| !f.enabled) { for fan in fans.iter().filter(|f| !f.enabled) {
debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}"); debug!("write_profile_curve_to_platform: writing profile:{profile}, {fan:?}");
@@ -208,7 +208,7 @@ impl FanCurveProfiles {
curve.enabled = enabled; curve.enabled = enabled;
} }
} }
PlatformProfile::Quiet => { PlatformProfile::Quiet | PlatformProfile::LowPower => {
for curve in self.quiet.iter_mut() { for curve in self.quiet.iter_mut() {
curve.enabled = enabled; curve.enabled = enabled;
} }
@@ -239,7 +239,7 @@ impl FanCurveProfiles {
} }
} }
} }
PlatformProfile::Quiet => { PlatformProfile::Quiet | PlatformProfile::LowPower => {
for curve in self.quiet.iter_mut() { for curve in self.quiet.iter_mut() {
if curve.fan == fan { if curve.fan == fan {
curve.enabled = enabled; curve.enabled = enabled;
@@ -254,7 +254,7 @@ impl FanCurveProfiles {
match name { match name {
PlatformProfile::Balanced => &self.balanced, PlatformProfile::Balanced => &self.balanced,
PlatformProfile::Performance => &self.performance, PlatformProfile::Performance => &self.performance,
PlatformProfile::Quiet => &self.quiet, PlatformProfile::Quiet | PlatformProfile::LowPower => &self.quiet,
} }
} }
@@ -274,7 +274,7 @@ impl FanCurveProfiles {
} }
} }
} }
PlatformProfile::Quiet => { PlatformProfile::Quiet | PlatformProfile::LowPower => {
for this_curve in self.quiet.iter() { for this_curve in self.quiet.iter() {
if this_curve.fan == pu { if this_curve.fan == pu {
return Some(this_curve); return Some(this_curve);
@@ -307,7 +307,7 @@ impl FanCurveProfiles {
} }
} }
} }
PlatformProfile::Quiet => { PlatformProfile::Quiet | PlatformProfile::LowPower => {
for this_curve in self.quiet.iter_mut() { for this_curve in self.quiet.iter_mut() {
if this_curve.fan == curve.fan { if this_curve.fan == curve.fan {
*this_curve = curve; *this_curve = curve;