mirror of
https://gitlab.steamos.cloud/holo/steamos-manager.git
synced 2025-07-05 06:00:30 -04:00
Merge branch 'endrift/platform-cleanup' into 'master'
Platform cleanup See merge request holo/steamos-manager!8
This commit is contained in:
commit
ee9d2332aa
13 changed files with 466 additions and 171 deletions
4
Makefile
4
Makefile
|
@ -24,9 +24,11 @@ install: target/release/steamos-manager target/release/steamosctl
|
|||
|
||||
install -Ds -m755 "target/release/steamos-manager" "$(DESTDIR)/usr/lib/steamos-manager"
|
||||
install -D -m755 "target/release/steamosctl" "$(DESTDIR)/usr/bin/steamosctl"
|
||||
install -D -m644 -t "$(DESTDIR)/usr/share/steamos-manager/platforms" "data/platforms/"*
|
||||
install -D -m644 -t "$(DESTDIR)/usr/share/steamos-manager/devices" "data/devices/"*
|
||||
install -D -m644 LICENSE "$(DESTDIR)/usr/share/licenses/steamos-manager/LICENSE"
|
||||
|
||||
install -m644 "data/platform.toml" "$(DESTDIR)/usr/share/steamos-manager/"
|
||||
|
||||
install -m644 "data/system/com.steampowered.SteamOSManager1.service" "$(DESTDIR)/usr/share/dbus-1/system-services/"
|
||||
install -m644 "data/system/com.steampowered.SteamOSManager1.conf" "$(DESTDIR)/usr/share/dbus-1/system.d/"
|
||||
install -m644 "data/system/steamos-manager.service" "$(DESTDIR)/usr/lib/systemd/system/"
|
||||
|
|
16
data/devices/jupiter.toml
Normal file
16
data/devices/jupiter.toml
Normal file
|
@ -0,0 +1,16 @@
|
|||
[tdp_limit]
|
||||
method = "gpu_hwmon"
|
||||
download_mode_limit = 6
|
||||
|
||||
[tdp_limit.range]
|
||||
min = 3
|
||||
max = 15
|
||||
|
||||
[gpu_clocks]
|
||||
min = 200
|
||||
max = 1600
|
||||
|
||||
[battery_charge_limit]
|
||||
suggested_minimum_limit = 10
|
||||
hwmon_name = "steamdeck_hwmon"
|
||||
attribute = "max_battery_charge_level"
|
|
@ -28,20 +28,3 @@ no_validate_flag = "--skip-validation"
|
|||
|
||||
[fan_control]
|
||||
systemd = "jupiter-fan-control.service"
|
||||
|
||||
[tdp_limit]
|
||||
method = "gpu_hwmon"
|
||||
download_mode_limit = 6
|
||||
|
||||
[tdp_limit.range]
|
||||
min = 3
|
||||
max = 15
|
||||
|
||||
[gpu_clocks]
|
||||
min = 200
|
||||
max = 1600
|
||||
|
||||
[battery_charge_limit]
|
||||
suggested_minimum_limit = 10
|
||||
hwmon_name = "steamdeck_hwmon"
|
||||
attribute = "max_battery_charge_level"
|
|
@ -483,19 +483,11 @@ pub mod test {
|
|||
|
||||
sleep(Duration::from_millis(10)).await;
|
||||
|
||||
h.test.platform_config.replace(Some(PlatformConfig {
|
||||
factory_reset: None,
|
||||
update_bios: None,
|
||||
update_dock: None,
|
||||
storage: None,
|
||||
fan_control: Some(ServiceConfig::Systemd(String::from(
|
||||
"jupiter-fan-control.service",
|
||||
))),
|
||||
tdp_limit: None,
|
||||
gpu_clocks: None,
|
||||
battery_charge_limit: None,
|
||||
performance_profile: None,
|
||||
}));
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.fan_control = Some(ServiceConfig::Systemd(String::from(
|
||||
"jupiter-fan-control.service",
|
||||
)));
|
||||
h.test.platform_config.replace(Some(platform_config));
|
||||
|
||||
let fan_control = FanControl::new(connection);
|
||||
assert_eq!(
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::hardware::{
|
|||
steam_deck_variant, FactoryResetKind, FanControl, FanControlState, SteamDeckVariant,
|
||||
};
|
||||
use crate::job::JobManager;
|
||||
use crate::platform::platform_config;
|
||||
use crate::platform::{device_config, platform_config};
|
||||
use crate::power::{
|
||||
set_cpu_scaling_governor, set_gpu_clocks, set_gpu_performance_level, set_gpu_power_profile,
|
||||
set_max_charge_level, set_platform_profile, tdp_limit_manager, CPUScalingGovernor,
|
||||
|
@ -450,7 +450,7 @@ impl SteamOSManager {
|
|||
}
|
||||
|
||||
async fn set_performance_profile(&self, profile: &str) -> fdo::Result<()> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = device_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
|
|
|
@ -24,7 +24,7 @@ use crate::hardware::{
|
|||
device_type, device_variant, steam_deck_variant, DeviceType, SteamDeckVariant,
|
||||
};
|
||||
use crate::job::JobManagerCommand;
|
||||
use crate::platform::platform_config;
|
||||
use crate::platform::{device_config, platform_config};
|
||||
use crate::power::{
|
||||
get_available_cpu_scaling_governors, get_available_gpu_performance_levels,
|
||||
get_available_gpu_power_profiles, get_available_platform_profiles, get_cpu_scaling_governor,
|
||||
|
@ -286,7 +286,7 @@ impl BatteryChargeLimit1 {
|
|||
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn suggested_minimum_limit(&self) -> i32 {
|
||||
let Ok(Some(ref config)) = platform_config().await else {
|
||||
let Ok(Some(ref config)) = device_config().await else {
|
||||
return BatteryChargeLimit1::DEFAULT_SUGGESTED_MINIMUM_LIMIT;
|
||||
};
|
||||
let Some(ref config) = config.battery_charge_limit else {
|
||||
|
@ -552,7 +552,7 @@ impl Manager2 {
|
|||
impl PerformanceProfile1 {
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn available_performance_profiles(&self) -> fdo::Result<Vec<String>> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = device_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
|
@ -566,7 +566,7 @@ impl PerformanceProfile1 {
|
|||
|
||||
#[zbus(property)]
|
||||
async fn performance_profile(&self) -> fdo::Result<String> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = device_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
|
@ -614,7 +614,7 @@ impl PerformanceProfile1 {
|
|||
|
||||
#[zbus(property(emits_changed_signal = "const"))]
|
||||
async fn suggested_default_performance_profile(&self) -> fdo::Result<String> {
|
||||
let config = platform_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = device_config().await.map_err(to_zbus_fdo_error)?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
|
@ -852,11 +852,11 @@ impl WifiPowerManagement1 {
|
|||
}
|
||||
}
|
||||
|
||||
async fn create_config_interfaces(
|
||||
async fn create_platform_interfaces(
|
||||
proxy: &Proxy<'static>,
|
||||
object_server: &ObjectServer,
|
||||
connection: &Connection,
|
||||
job_manager: &UnboundedSender<JobManagerCommand>,
|
||||
tdp_manager: Option<UnboundedSender<TdpManagerCommand>>,
|
||||
) -> Result<()> {
|
||||
let Some(config) = platform_config().await? else {
|
||||
return Ok(());
|
||||
|
@ -868,10 +868,6 @@ async fn create_config_interfaces(
|
|||
let fan_control = FanControl1 {
|
||||
proxy: proxy.clone(),
|
||||
};
|
||||
let performance_profile = PerformanceProfile1 {
|
||||
proxy: proxy.clone(),
|
||||
tdp_limit_manager: tdp_manager.clone(),
|
||||
};
|
||||
let storage = Storage1 {
|
||||
proxy: proxy.clone(),
|
||||
job_manager: job_manager.clone(),
|
||||
|
@ -885,14 +881,73 @@ async fn create_config_interfaces(
|
|||
job_manager: job_manager.clone(),
|
||||
};
|
||||
|
||||
if config.factory_reset.is_some() {
|
||||
object_server.at(MANAGER_PATH, factory_reset).await?;
|
||||
if let Some(config) = config.factory_reset.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, factory_reset).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if factory reset config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
if config.fan_control.is_some() {
|
||||
object_server.at(MANAGER_PATH, fan_control).await?;
|
||||
if let Some(config) = config.fan_control.as_ref() {
|
||||
match config.is_valid(connection, true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, fan_control).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if fan control config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(config) = config.storage.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, storage).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if storage config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(config) = config.update_bios.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, update_bios).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if BIOS update config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(config) = config.update_dock.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, update_dock).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if dock update config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_device_interfaces(
|
||||
proxy: &Proxy<'static>,
|
||||
object_server: &ObjectServer,
|
||||
tdp_manager: Option<UnboundedSender<TdpManagerCommand>>,
|
||||
) -> Result<()> {
|
||||
let Some(config) = device_config().await? else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let performance_profile = PerformanceProfile1 {
|
||||
proxy: proxy.clone(),
|
||||
tdp_limit_manager: tdp_manager.clone(),
|
||||
};
|
||||
|
||||
if let Some(manager) = tdp_manager {
|
||||
let low_power_mode = LowPowerMode1 {
|
||||
manager: manager.clone(),
|
||||
|
@ -918,7 +973,7 @@ async fn create_config_interfaces(
|
|||
});
|
||||
}
|
||||
|
||||
if let Some(ref config) = config.performance_profile {
|
||||
if let Some(config) = config.performance_profile.as_ref() {
|
||||
if !get_available_platform_profiles(&config.platform_profile_name)
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
|
@ -928,34 +983,9 @@ async fn create_config_interfaces(
|
|||
}
|
||||
}
|
||||
|
||||
if config.storage.is_some() {
|
||||
object_server.at(MANAGER_PATH, storage).await?;
|
||||
}
|
||||
|
||||
if let Some(config) = config.update_bios.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, update_bios).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if BIOS update config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(config) = config.update_dock.as_ref() {
|
||||
match config.is_valid(true).await {
|
||||
Ok(true) => {
|
||||
object_server.at(MANAGER_PATH, update_dock).await?;
|
||||
}
|
||||
Ok(false) => (),
|
||||
Err(e) => error!("Failed to verify if dock update config is valid: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub(crate) async fn create_interfaces(
|
||||
session: Connection,
|
||||
system: Connection,
|
||||
|
@ -1007,7 +1037,8 @@ pub(crate) async fn create_interfaces(
|
|||
let object_server = session.object_server();
|
||||
object_server.at(MANAGER_PATH, manager).await?;
|
||||
|
||||
create_config_interfaces(&proxy, object_server, &job_manager, tdp_manager).await?;
|
||||
create_device_interfaces(&proxy, object_server, tdp_manager).await?;
|
||||
create_platform_interfaces(&proxy, object_server, &system, &job_manager).await?;
|
||||
|
||||
if device_type().await.unwrap_or_default() == DeviceType::SteamDeck {
|
||||
object_server.at(MANAGER_PATH, als).await?;
|
||||
|
@ -1069,8 +1100,9 @@ mod test {
|
|||
use crate::hardware::test::fake_model;
|
||||
use crate::hardware::SteamDeckVariant;
|
||||
use crate::platform::{
|
||||
BatteryChargeLimitConfig, PerformanceProfileConfig, PlatformConfig, RangeConfig,
|
||||
ResetConfig, ScriptConfig, ServiceConfig, StorageConfig, TdpLimitConfig,
|
||||
BatteryChargeLimitConfig, DeviceConfig, FormatDeviceConfig, PerformanceProfileConfig,
|
||||
PlatformConfig, RangeConfig, ResetConfig, ScriptConfig, ServiceConfig, StorageConfig,
|
||||
TdpLimitConfig,
|
||||
};
|
||||
use crate::power::TdpLimitingMethod;
|
||||
use crate::systemd::test::{MockManager, MockUnit};
|
||||
|
@ -1078,6 +1110,7 @@ mod test {
|
|||
|
||||
use std::num::NonZeroU32;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use tokio::fs::{set_permissions, write};
|
||||
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
|
||||
|
@ -1092,7 +1125,7 @@ mod test {
|
|||
rx_tdp: Option<UnboundedReceiver<TdpManagerCommand>>,
|
||||
}
|
||||
|
||||
fn all_config() -> Option<PlatformConfig> {
|
||||
fn all_platform_config() -> Option<PlatformConfig> {
|
||||
Some(PlatformConfig {
|
||||
factory_reset: Some(ResetConfig::default()),
|
||||
update_bios: Some(ScriptConfig::default()),
|
||||
|
@ -1101,6 +1134,11 @@ mod test {
|
|||
fan_control: Some(ServiceConfig::Systemd(String::from(
|
||||
"jupiter-fan-control.service",
|
||||
))),
|
||||
})
|
||||
}
|
||||
|
||||
fn all_device_config() -> Option<DeviceConfig> {
|
||||
Some(DeviceConfig {
|
||||
tdp_limit: Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::GpuHwmon,
|
||||
range: Some(RangeConfig::new(3, 15)),
|
||||
|
@ -1120,12 +1158,15 @@ mod test {
|
|||
})
|
||||
}
|
||||
|
||||
async fn start(mut platform_config: Option<PlatformConfig>) -> Result<TestHandle> {
|
||||
async fn start(
|
||||
mut platform_config: Option<PlatformConfig>,
|
||||
device_config: Option<DeviceConfig>,
|
||||
) -> Result<TestHandle> {
|
||||
let mut handle = testing::start();
|
||||
let (tx_ctx, _rx_ctx) = channel::<UserContext>();
|
||||
let (tx_job, rx_job) = unbounded_channel::<JobManagerCommand>();
|
||||
let (tx_tdp, rx_tdp) = {
|
||||
if platform_config
|
||||
if device_config
|
||||
.as_ref()
|
||||
.and_then(|config| config.tdp_limit.as_ref())
|
||||
.is_some()
|
||||
|
@ -1142,6 +1183,7 @@ mod test {
|
|||
}
|
||||
|
||||
handle.test.platform_config.replace(platform_config);
|
||||
handle.test.device_config.replace(device_config);
|
||||
let connection = handle.new_dbus().await?;
|
||||
connection.request_name("org.freedesktop.systemd1").await?;
|
||||
sleep(Duration::from_millis(10)).await;
|
||||
|
@ -1192,7 +1234,7 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
let remote = testing::InterfaceIntrospection::from_remote::<SteamOSManager, _>(
|
||||
&test.connection,
|
||||
|
@ -1228,7 +1270,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_ambient_light_sensor1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(
|
||||
test_interface_matches::<AmbientLightSensor1>(&test.connection)
|
||||
|
@ -1239,7 +1283,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_battery_charge_limit() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(
|
||||
test_interface_matches::<BatteryChargeLimit1>(&test.connection)
|
||||
|
@ -1250,7 +1296,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_cpu_scaling1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<CpuScaling1>(&test.connection)
|
||||
.await
|
||||
|
@ -1259,7 +1307,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_factory_reset1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<FactoryReset1>(&test.connection)
|
||||
.await
|
||||
|
@ -1268,14 +1318,52 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_factory_reset1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<FactoryReset1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_all_factory_reset1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.factory_reset.as_mut().unwrap().all = ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
};
|
||||
let test = start(Some(config), None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<FactoryReset1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_os_factory_reset1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.factory_reset.as_mut().unwrap().os = ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
};
|
||||
let test = start(Some(config), None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<FactoryReset1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_user_factory_reset1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.factory_reset.as_mut().unwrap().user = ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
};
|
||||
let test = start(Some(config), None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<FactoryReset1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_fan_control1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<FanControl1>(&test.connection)
|
||||
.await
|
||||
|
@ -1284,14 +1372,16 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_fan_control1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<FanControl1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_gpu_performance_level1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(
|
||||
test_interface_matches::<GpuPerformanceLevel1>(&test.connection)
|
||||
|
@ -1302,7 +1392,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_gpu_power_profile1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<GpuPowerProfile1>(&test.connection)
|
||||
.await
|
||||
|
@ -1311,7 +1403,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_tdp_limit1() {
|
||||
let mut test = start(all_config()).await.expect("start");
|
||||
let mut test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
let TdpManagerCommand::IsActive(reply) =
|
||||
test.rx_tdp.as_mut().unwrap().recv().await.unwrap()
|
||||
|
@ -1328,14 +1422,16 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_tdp_limit1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<TdpLimit1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_inactive_tdp_limit1() {
|
||||
let mut test = start(all_config()).await.expect("start");
|
||||
let mut test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
let TdpManagerCommand::IsActive(reply) =
|
||||
test.rx_tdp.as_mut().unwrap().recv().await.unwrap()
|
||||
|
@ -1350,7 +1446,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_hdmi_cec1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<HdmiCec1>(&test.connection)
|
||||
.await
|
||||
|
@ -1359,7 +1457,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_low_power_mode1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<LowPowerMode1>(&test.connection)
|
||||
.await
|
||||
|
@ -1368,14 +1468,16 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_low_power_mode1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<LowPowerMode1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_manager2() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<Manager2>(&test.connection)
|
||||
.await
|
||||
|
@ -1384,7 +1486,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_performance_profile1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(
|
||||
test_interface_matches::<PerformanceProfile1>(&test.connection)
|
||||
|
@ -1395,14 +1499,16 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_performance_profile1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<PerformanceProfile1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_storage1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<Storage1>(&test.connection)
|
||||
.await
|
||||
|
@ -1411,14 +1517,43 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_storage1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<Storage1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_trim_storage1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.storage.as_mut().unwrap().trim_devices = ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
};
|
||||
let test = start(Some(config), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<Storage1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_format_storage1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
let mut format_config = FormatDeviceConfig::default();
|
||||
format_config.script = PathBuf::from("oxo");
|
||||
config.storage.as_mut().unwrap().format_device = format_config;
|
||||
let test = start(Some(config), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<Storage1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_update_bios1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<UpdateBios1>(&test.connection)
|
||||
.await
|
||||
|
@ -1427,14 +1562,30 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_update_bios1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<UpdateBios1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_update_bios1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.update_bios = Some(ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
});
|
||||
let test = start(Some(config), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<UpdateBios1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_update_dock1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<UpdateDock1>(&test.connection)
|
||||
.await
|
||||
|
@ -1443,14 +1594,30 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_update_dock1() {
|
||||
let test = start(None).await.expect("start");
|
||||
let test = start(None, None).await.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<UpdateDock1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_missing_invalid_update_dock1() {
|
||||
let mut config = all_platform_config().unwrap();
|
||||
config.update_dock = Some(ScriptConfig {
|
||||
script: PathBuf::from("oxo"),
|
||||
script_args: Vec::new(),
|
||||
});
|
||||
let test = start(Some(config), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_missing::<UpdateDock1>(&test.connection).await);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_wifi_power_management1() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(
|
||||
test_interface_matches::<WifiPowerManagement1>(&test.connection)
|
||||
|
@ -1461,7 +1628,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_wifi_debug() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<WifiDebug1>(&test.connection)
|
||||
.await
|
||||
|
@ -1470,7 +1639,9 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn interface_matches_wifi_debug_dump() {
|
||||
let test = start(all_config()).await.expect("start");
|
||||
let test = start(all_platform_config(), all_device_config())
|
||||
.await
|
||||
.expect("start");
|
||||
|
||||
assert!(test_interface_matches::<WifiDebugDump1>(&test.connection)
|
||||
.await
|
||||
|
|
145
src/platform.rs
145
src/platform.rs
|
@ -19,13 +19,19 @@ use tokio::fs::{metadata, read_to_string};
|
|||
#[cfg(not(test))]
|
||||
use tokio::sync::OnceCell;
|
||||
use tokio::task::spawn_blocking;
|
||||
use zbus::Connection;
|
||||
|
||||
#[cfg(not(test))]
|
||||
use crate::hardware::{device_type, DeviceType};
|
||||
#[cfg(test)]
|
||||
use crate::path;
|
||||
use crate::power::TdpLimitingMethod;
|
||||
use crate::systemd::SystemdUnit;
|
||||
|
||||
#[cfg(not(test))]
|
||||
static CONFIG: OnceCell<Option<PlatformConfig>> = OnceCell::const_new();
|
||||
static PLATFORM_CONFIG: OnceCell<Option<PlatformConfig>> = OnceCell::const_new();
|
||||
#[cfg(not(test))]
|
||||
static DEVICE_CONFIG: OnceCell<Option<DeviceConfig>> = OnceCell::const_new();
|
||||
|
||||
#[derive(Clone, Default, Deserialize, Debug)]
|
||||
#[serde(default)]
|
||||
|
@ -35,6 +41,11 @@ pub(crate) struct PlatformConfig {
|
|||
pub update_dock: Option<ScriptConfig>,
|
||||
pub storage: Option<StorageConfig>,
|
||||
pub fan_control: Option<ServiceConfig>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Deserialize, Debug)]
|
||||
#[serde(default)]
|
||||
pub(crate) struct DeviceConfig {
|
||||
pub tdp_limit: Option<TdpLimitConfig>,
|
||||
pub gpu_clocks: Option<RangeConfig<u32>>,
|
||||
pub battery_charge_limit: Option<BatteryChargeLimitConfig>,
|
||||
|
@ -93,6 +104,14 @@ pub(crate) struct ResetConfig {
|
|||
pub user: ScriptConfig,
|
||||
}
|
||||
|
||||
impl ResetConfig {
|
||||
pub(crate) async fn is_valid(&self, root: bool) -> Result<bool> {
|
||||
Ok(self.all.is_valid(root).await?
|
||||
&& self.os.is_valid(root).await?
|
||||
&& self.user.is_valid(root).await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Debug)]
|
||||
pub(crate) enum ServiceConfig {
|
||||
#[serde(rename = "systemd")]
|
||||
|
@ -105,12 +124,33 @@ pub(crate) enum ServiceConfig {
|
|||
},
|
||||
}
|
||||
|
||||
impl ServiceConfig {
|
||||
pub(crate) async fn is_valid(&self, connection: &Connection, root: bool) -> Result<bool> {
|
||||
match self {
|
||||
ServiceConfig::Systemd(unit) => SystemdUnit::exists(connection, unit).await,
|
||||
ServiceConfig::Script {
|
||||
start,
|
||||
stop,
|
||||
status,
|
||||
} => Ok(start.is_valid(root).await?
|
||||
&& stop.is_valid(root).await?
|
||||
&& status.is_valid(root).await?),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Deserialize, Debug)]
|
||||
pub(crate) struct StorageConfig {
|
||||
pub trim_devices: ScriptConfig,
|
||||
pub format_device: FormatDeviceConfig,
|
||||
}
|
||||
|
||||
impl StorageConfig {
|
||||
pub(crate) async fn is_valid(&self, root: bool) -> Result<bool> {
|
||||
Ok(self.trim_devices.is_valid(root).await? && self.format_device.is_valid(root).await?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Debug)]
|
||||
pub(crate) struct BatteryChargeLimitConfig {
|
||||
pub suggested_minimum_limit: Option<i32>,
|
||||
|
@ -153,6 +193,36 @@ pub(crate) struct FormatDeviceConfig {
|
|||
pub no_validate_flag: Option<String>,
|
||||
}
|
||||
|
||||
impl FormatDeviceConfig {
|
||||
pub(crate) async fn is_valid(&self, root: bool) -> Result<bool> {
|
||||
let meta = match metadata(&self.script).await {
|
||||
Ok(meta) => meta,
|
||||
Err(e) if [ErrorKind::NotFound, ErrorKind::PermissionDenied].contains(&e.kind()) => {
|
||||
return Ok(false)
|
||||
}
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
if !meta.is_file() {
|
||||
return Ok(false);
|
||||
}
|
||||
if root {
|
||||
let script = self.script.clone();
|
||||
if !spawn_blocking(move || match access(&script, AccessFlags::X_OK) {
|
||||
Ok(()) => Ok(true),
|
||||
Err(Errno::ENOENT | Errno::EACCES) => Ok(false),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.await??
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
} else if (meta.mode() & 0o111) == 0 {
|
||||
return Ok(false);
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> RangeConfig<T> {
|
||||
#[allow(unused)]
|
||||
pub(crate) fn new(min: T, max: T) -> RangeConfig<T> {
|
||||
|
@ -163,6 +233,47 @@ impl<T: Clone> RangeConfig<T> {
|
|||
impl PlatformConfig {
|
||||
#[cfg(not(test))]
|
||||
async fn load() -> Result<Option<PlatformConfig>> {
|
||||
let config = read_to_string("/usr/share/steamos-manager/platform.toml").await?;
|
||||
Ok(Some(toml::from_str(config.as_ref())?))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn set_test_paths(&mut self) {
|
||||
if let Some(ref mut factory_reset) = self.factory_reset {
|
||||
if factory_reset.all.script.as_os_str().is_empty() {
|
||||
factory_reset.all.script = path("exe");
|
||||
}
|
||||
if factory_reset.os.script.as_os_str().is_empty() {
|
||||
factory_reset.os.script = path("exe");
|
||||
}
|
||||
if factory_reset.user.script.as_os_str().is_empty() {
|
||||
factory_reset.user.script = path("exe");
|
||||
}
|
||||
}
|
||||
if let Some(ref mut storage) = self.storage {
|
||||
if storage.trim_devices.script.as_os_str().is_empty() {
|
||||
storage.trim_devices.script = path("exe");
|
||||
}
|
||||
if storage.format_device.script.as_os_str().is_empty() {
|
||||
storage.format_device.script = path("exe");
|
||||
}
|
||||
}
|
||||
if let Some(ref mut update_bios) = self.update_bios {
|
||||
if update_bios.script.as_os_str().is_empty() {
|
||||
update_bios.script = path("exe");
|
||||
}
|
||||
}
|
||||
if let Some(ref mut update_dock) = self.update_dock {
|
||||
if update_dock.script.as_os_str().is_empty() {
|
||||
update_dock.script = path("exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceConfig {
|
||||
#[cfg(not(test))]
|
||||
async fn load() -> Result<Option<DeviceConfig>> {
|
||||
let platform = match device_type().await? {
|
||||
DeviceType::SteamDeck => "jupiter",
|
||||
DeviceType::LegionGo => "legion-go-series",
|
||||
|
@ -173,25 +284,11 @@ impl PlatformConfig {
|
|||
_ => return Ok(None),
|
||||
};
|
||||
let config = read_to_string(format!(
|
||||
"/usr/share/steamos-manager/platforms/{platform}.toml"
|
||||
"/usr/share/steamos-manager/devices/{platform}.toml"
|
||||
))
|
||||
.await?;
|
||||
Ok(Some(toml::from_str(config.as_ref())?))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn set_test_paths(&mut self) {
|
||||
if let Some(ref mut update_bios) = self.update_bios {
|
||||
if update_bios.script.as_os_str().is_empty() {
|
||||
update_bios.script = crate::path("exe");
|
||||
}
|
||||
}
|
||||
if let Some(ref mut update_dock) = self.update_dock {
|
||||
if update_dock.script.as_os_str().is_empty() {
|
||||
update_dock.script = crate::path("exe");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn de_tdp_limiter_method<'de, D>(deserializer: D) -> Result<TdpLimitingMethod, D::Error>
|
||||
|
@ -206,7 +303,12 @@ where
|
|||
|
||||
#[cfg(not(test))]
|
||||
pub(crate) async fn platform_config() -> Result<&'static Option<PlatformConfig>> {
|
||||
CONFIG.get_or_try_init(PlatformConfig::load).await
|
||||
PLATFORM_CONFIG.get_or_try_init(PlatformConfig::load).await
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub(crate) async fn device_config() -> Result<&'static Option<DeviceConfig>> {
|
||||
DEVICE_CONFIG.get_or_try_init(DeviceConfig::load).await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -216,6 +318,13 @@ pub(crate) async fn platform_config() -> Result<Option<PlatformConfig>> {
|
|||
Ok(config)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) async fn device_config() -> Result<Option<DeviceConfig>> {
|
||||
let test = crate::testing::current();
|
||||
let config = test.device_config.borrow().clone();
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
@ -329,7 +438,7 @@ mod test {
|
|||
|
||||
#[tokio::test]
|
||||
async fn jupiter_valid() {
|
||||
let config = read_to_string("data/platforms/jupiter.toml")
|
||||
let config = read_to_string("data/devices/jupiter.toml")
|
||||
.await
|
||||
.expect("read_to_string");
|
||||
let res = toml::from_str::<PlatformConfig>(config.as_ref());
|
||||
|
|
64
src/power.rs
64
src/power.rs
|
@ -30,7 +30,7 @@ use zbus::Connection;
|
|||
use crate::hardware::{device_type, DeviceType};
|
||||
use crate::manager::root::RootManagerProxy;
|
||||
use crate::manager::user::{TdpLimit1, MANAGER_PATH};
|
||||
use crate::platform::platform_config;
|
||||
use crate::platform::device_config;
|
||||
use crate::Service;
|
||||
use crate::{path, write_synced};
|
||||
|
||||
|
@ -128,7 +128,7 @@ pub(crate) trait TdpLimitManager: Send + Sync {
|
|||
}
|
||||
|
||||
pub(crate) async fn tdp_limit_manager() -> Result<Box<dyn TdpLimitManager>> {
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.tdp_limit.as_ref())
|
||||
|
@ -340,7 +340,7 @@ pub(crate) async fn set_cpu_scaling_governor(governor: CPUScalingGovernor) -> Re
|
|||
}
|
||||
|
||||
pub(crate) async fn get_gpu_clocks_range() -> Result<RangeInclusive<u32>> {
|
||||
if let Some(range) = platform_config()
|
||||
if let Some(range) = device_config()
|
||||
.await?
|
||||
.as_ref()
|
||||
.and_then(|config| config.gpu_clocks)
|
||||
|
@ -490,7 +490,7 @@ impl TdpLimitManager for GpuHwmonTdpLimitManager {
|
|||
}
|
||||
|
||||
async fn get_tdp_limit_range(&self) -> Result<RangeInclusive<u32>> {
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.tdp_limit.as_ref())
|
||||
|
@ -578,7 +578,7 @@ impl TdpLimitManager for FirmwareAttributeLimitManager {
|
|||
let Some(ref performance_profile) = self.performance_profile else {
|
||||
return Ok(true);
|
||||
};
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
if let Some(config) = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.performance_profile.as_ref())
|
||||
|
@ -591,7 +591,7 @@ impl TdpLimitManager for FirmwareAttributeLimitManager {
|
|||
}
|
||||
|
||||
pub(crate) async fn get_max_charge_level() -> Result<i32> {
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.battery_charge_limit.as_ref())
|
||||
|
@ -609,7 +609,7 @@ pub(crate) async fn get_max_charge_level() -> Result<i32> {
|
|||
pub(crate) async fn set_max_charge_level(limit: i32) -> Result<()> {
|
||||
ensure!((0..=100).contains(&limit), "Invalid limit");
|
||||
let data = limit.to_string();
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.battery_charge_limit.as_ref())
|
||||
|
@ -654,7 +654,7 @@ impl TdpManagerService {
|
|||
system: &Connection,
|
||||
session: &Connection,
|
||||
) -> Result<TdpManagerService> {
|
||||
let config = platform_config().await?;
|
||||
let config = device_config().await?;
|
||||
let config = config
|
||||
.as_ref()
|
||||
.and_then(|config| config.tdp_limit.as_ref())
|
||||
|
@ -858,8 +858,8 @@ pub(crate) mod test {
|
|||
use crate::hardware::test::fake_model;
|
||||
use crate::hardware::SteamDeckVariant;
|
||||
use crate::platform::{
|
||||
BatteryChargeLimitConfig, FirmwareAttributeConfig, PerformanceProfileConfig,
|
||||
PlatformConfig, RangeConfig, TdpLimitConfig,
|
||||
BatteryChargeLimitConfig, DeviceConfig, FirmwareAttributeConfig, PerformanceProfileConfig,
|
||||
RangeConfig, TdpLimitConfig,
|
||||
};
|
||||
use crate::{enum_roundtrip, testing};
|
||||
use anyhow::anyhow;
|
||||
|
@ -1041,14 +1041,14 @@ CCLK_RANGE in Core0:
|
|||
async fn test_gpu_hwmon_get_tdp_limit() {
|
||||
let handle = testing::start();
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::GpuHwmon,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: None,
|
||||
firmware_attribute: None,
|
||||
});
|
||||
handle.test.platform_config.replace(Some(platform_config));
|
||||
handle.test.device_config.replace(Some(config));
|
||||
let manager = tdp_limit_manager().await.unwrap();
|
||||
|
||||
setup().await.expect("setup");
|
||||
|
@ -1066,14 +1066,14 @@ CCLK_RANGE in Core0:
|
|||
async fn test_gpu_hwmon_set_tdp_limit() {
|
||||
let handle = testing::start();
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::GpuHwmon,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: None,
|
||||
firmware_attribute: None,
|
||||
});
|
||||
handle.test.platform_config.replace(Some(platform_config));
|
||||
handle.test.device_config.replace(Some(config));
|
||||
let manager = tdp_limit_manager().await.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
|
@ -1550,13 +1550,13 @@ CCLK_RANGE in Core0:
|
|||
async fn read_max_charge_level() {
|
||||
let handle = testing::start();
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.battery_charge_limit = Some(BatteryChargeLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.battery_charge_limit = Some(BatteryChargeLimitConfig {
|
||||
suggested_minimum_limit: Some(10),
|
||||
hwmon_name: String::from("steamdeck_hwmon"),
|
||||
attribute: String::from("max_battery_charge_level"),
|
||||
});
|
||||
handle.test.platform_config.replace(Some(platform_config));
|
||||
handle.test.device_config.replace(Some(config));
|
||||
|
||||
let base = path(HWMON_PREFIX).join("hwmon6");
|
||||
create_dir_all(&base).await.expect("create_dir_all");
|
||||
|
@ -1650,14 +1650,14 @@ CCLK_RANGE in Core0:
|
|||
|
||||
let iface = MockTdpLimit { queue: reply_tx };
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::GpuHwmon,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: NonZeroU32::new(6),
|
||||
firmware_attribute: None,
|
||||
});
|
||||
h.test.platform_config.replace(Some(platform_config));
|
||||
h.test.device_config.replace(Some(config));
|
||||
let manager = tdp_limit_manager().await.unwrap();
|
||||
|
||||
connection
|
||||
|
@ -1746,14 +1746,14 @@ CCLK_RANGE in Core0:
|
|||
|
||||
let iface = MockTdpLimit { queue: reply_tx };
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::GpuHwmon,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: None,
|
||||
firmware_attribute: None,
|
||||
});
|
||||
h.test.platform_config.replace(Some(platform_config));
|
||||
h.test.device_config.replace(Some(config));
|
||||
let manager = tdp_limit_manager().await.unwrap();
|
||||
|
||||
connection
|
||||
|
@ -1808,12 +1808,12 @@ CCLK_RANGE in Core0:
|
|||
let h = testing::start();
|
||||
setup().await.expect("setup");
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.performance_profile = Some(PerformanceProfileConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.performance_profile = Some(PerformanceProfileConfig {
|
||||
platform_profile_name: String::from("platform-profile0"),
|
||||
suggested_default: String::from("custom"),
|
||||
});
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::FirmwareAttribute,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: None,
|
||||
|
@ -1822,7 +1822,7 @@ CCLK_RANGE in Core0:
|
|||
performance_profile: Some(String::from("custom")),
|
||||
}),
|
||||
});
|
||||
h.test.platform_config.replace(Some(platform_config));
|
||||
h.test.device_config.replace(Some(config));
|
||||
|
||||
let attributes_base = path(FirmwareAttributeLimitManager::PREFIX)
|
||||
.join("tdp0")
|
||||
|
@ -1903,8 +1903,8 @@ CCLK_RANGE in Core0:
|
|||
let h = testing::start();
|
||||
setup().await.expect("setup");
|
||||
|
||||
let mut platform_config = PlatformConfig::default();
|
||||
platform_config.tdp_limit = Some(TdpLimitConfig {
|
||||
let mut config = DeviceConfig::default();
|
||||
config.tdp_limit = Some(TdpLimitConfig {
|
||||
method: TdpLimitingMethod::FirmwareAttribute,
|
||||
range: Some(RangeConfig { min: 3, max: 15 }),
|
||||
download_mode_limit: None,
|
||||
|
@ -1913,7 +1913,7 @@ CCLK_RANGE in Core0:
|
|||
performance_profile: None,
|
||||
}),
|
||||
});
|
||||
h.test.platform_config.replace(Some(platform_config));
|
||||
h.test.device_config.replace(Some(config));
|
||||
|
||||
let attributes_base = path(FirmwareAttributeLimitManager::PREFIX)
|
||||
.join("tdp0")
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::str::FromStr;
|
|||
use strum::{Display, EnumString};
|
||||
use zbus::proxy::CacheProperties;
|
||||
use zbus::zvariant::OwnedObjectPath;
|
||||
use zbus::Connection;
|
||||
use zbus::{self, Connection};
|
||||
|
||||
#[zbus::proxy(
|
||||
interface = "org.freedesktop.systemd1.Unit",
|
||||
|
@ -19,13 +19,13 @@ use zbus::Connection;
|
|||
)]
|
||||
trait SystemdUnit {
|
||||
#[zbus(property)]
|
||||
fn active_state(&self) -> Result<String>;
|
||||
fn active_state(&self) -> zbus::Result<String>;
|
||||
#[zbus(property)]
|
||||
fn unit_file_state(&self) -> Result<String>;
|
||||
fn unit_file_state(&self) -> zbus::Result<String>;
|
||||
|
||||
async fn restart(&self, mode: &str) -> Result<OwnedObjectPath>;
|
||||
async fn start(&self, mode: &str) -> Result<OwnedObjectPath>;
|
||||
async fn stop(&self, mode: &str) -> Result<OwnedObjectPath>;
|
||||
async fn restart(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
async fn start(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
async fn stop(&self, mode: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
}
|
||||
|
||||
#[zbus::proxy(
|
||||
|
@ -40,28 +40,30 @@ trait SystemdManager {
|
|||
files: &[&str],
|
||||
runtime: bool,
|
||||
force: bool,
|
||||
) -> Result<(bool, Vec<(String, String, String)>)>;
|
||||
) -> zbus::Result<(bool, Vec<(String, String, String)>)>;
|
||||
|
||||
async fn disable_unit_files(
|
||||
&self,
|
||||
files: &[&str],
|
||||
runtime: bool,
|
||||
) -> Result<Vec<(String, String, String)>>;
|
||||
) -> zbus::Result<Vec<(String, String, String)>>;
|
||||
|
||||
async fn mask_unit_files(
|
||||
&self,
|
||||
files: &[&str],
|
||||
runtime: bool,
|
||||
force: bool,
|
||||
) -> Result<Vec<(String, String, String)>>;
|
||||
) -> zbus::Result<Vec<(String, String, String)>>;
|
||||
|
||||
async fn unmask_unit_files(
|
||||
&self,
|
||||
files: &[&str],
|
||||
runtime: bool,
|
||||
) -> Result<Vec<(String, String, String)>>;
|
||||
) -> zbus::Result<Vec<(String, String, String)>>;
|
||||
|
||||
async fn reload(&self) -> Result<()>;
|
||||
async fn reload(&self) -> zbus::Result<()>;
|
||||
|
||||
async fn get_unit(&self, name: &str) -> zbus::Result<OwnedObjectPath>;
|
||||
}
|
||||
|
||||
#[derive(Display, EnumString, PartialEq, Debug, Copy, Clone)]
|
||||
|
@ -86,6 +88,17 @@ pub async fn daemon_reload(connection: &Connection) -> Result<()> {
|
|||
}
|
||||
|
||||
impl<'dbus> SystemdUnit<'dbus> {
|
||||
pub async fn exists(connection: &Connection, name: &str) -> Result<bool> {
|
||||
let manager = SystemdManagerProxy::new(connection).await?;
|
||||
// This is kinda hacky, but zbus makes it pretty hard to get the proper error name
|
||||
let expected_error = format!("Unit {name} not loaded.");
|
||||
match manager.get_unit(name).await {
|
||||
Ok(_) => Ok(true),
|
||||
Err(zbus::Error::Failure(message)) if message == expected_error => Ok(false),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn new(connection: Connection, name: &str) -> Result<SystemdUnit<'dbus>> {
|
||||
let path = PathBuf::from("/org/freedesktop/systemd1/unit").join(escape(name));
|
||||
let path = String::from(path.to_str().ok_or(anyhow!("Unit name {name} invalid"))?);
|
||||
|
@ -283,7 +296,6 @@ pub mod test {
|
|||
.interface::<_, MockUnit>(path.to_string_lossy())
|
||||
.await;
|
||||
if let Ok(mock_unit) = mock_unit {
|
||||
dbg!();
|
||||
mock_unit.get_mut().await.unit_file = String::from("enabled");
|
||||
}
|
||||
}
|
||||
|
@ -359,6 +371,14 @@ pub mod test {
|
|||
async fn reload(&self) -> fdo::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_unit(&mut self, unit: &str) -> fdo::Result<OwnedObjectPath> {
|
||||
Ok(
|
||||
ObjectPath::try_from(format!("/org/freedesktop/systemd1/unit/{}", escape(unit)))
|
||||
.unwrap()
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
|
|
@ -23,7 +23,7 @@ use zbus::zvariant::ObjectPath;
|
|||
use zbus::Address;
|
||||
use zbus_xml::{Method, Node, Property, Signal};
|
||||
|
||||
use crate::platform::PlatformConfig;
|
||||
use crate::platform::{DeviceConfig, PlatformConfig};
|
||||
|
||||
thread_local! {
|
||||
static TEST: RefCell<Option<Rc<Test>>> = const { RefCell::new(None) };
|
||||
|
@ -70,6 +70,7 @@ pub fn start() -> TestHandle {
|
|||
mock_dbus: Cell::new(None),
|
||||
dbus_address: Mutex::new(None),
|
||||
platform_config: RefCell::new(None),
|
||||
device_config: RefCell::new(None),
|
||||
});
|
||||
*lock.borrow_mut() = Some(test.clone());
|
||||
TestHandle { test }
|
||||
|
@ -103,6 +104,7 @@ pub struct Test {
|
|||
pub mock_dbus: Cell<Option<MockDBus>>,
|
||||
pub dbus_address: Mutex<Option<Address>>,
|
||||
pub platform_config: RefCell<Option<PlatformConfig>>,
|
||||
pub device_config: RefCell<Option<DeviceConfig>>,
|
||||
}
|
||||
|
||||
pub struct TestHandle {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue