From fba5f26f7e9061916d0c6f5155cb8d6f60eb8f94 Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Thu, 11 Mar 2021 10:53:01 +1300 Subject: [PATCH] More verbose and thorough checks for gfx switching - Small fixes - Cleanup bios help - g-sync warnings on toggling --- CHANGELOG.md | 6 ++ Cargo.lock | 4 +- asusctl/Cargo.toml | 2 +- asusctl/src/main.rs | 160 ++++++++++++++++++++++------------- daemon/Cargo.toml | 2 +- daemon/src/ctrl_gfx/error.rs | 14 ++- daemon/src/ctrl_gfx/gfx.rs | 87 ++++++++++++++++--- daemon/src/ctrl_gfx/mod.rs | 2 + daemon/src/ctrl_rog_bios.rs | 5 +- daemon/src/daemon.rs | 3 +- rog-types/src/profile.rs | 6 +- 11 files changed, 206 insertions(+), 85 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b39d3488..9972002e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Changed +- Further tweaks to gfx switching +- More logging on gfx switching +- Filter bios help according to supported modes +- Prevent gfx mode switching if in dedicated/G-Sync mode + # [3.1.4] - 2021-03-10 ### Changed - Notify through dbus if user changes profile manually diff --git a/Cargo.lock b/Cargo.lock index f822da9a..3ca06e01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,7 +33,7 @@ dependencies = [ [[package]] name = "asusctl" -version = "3.1.1" +version = "3.1.2" dependencies = [ "daemon", "gumdrop", @@ -188,7 +188,7 @@ dependencies = [ [[package]] name = "daemon" -version = "3.1.4" +version = "3.1.5" dependencies = [ "env_logger", "intel-pstate", diff --git a/asusctl/Cargo.toml b/asusctl/Cargo.toml index 61184197..bc63900f 100644 --- a/asusctl/Cargo.toml +++ b/asusctl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "asusctl" -version = "3.1.1" +version = "3.1.2" authors = ["Luke D Jones "] edition = "2018" diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 78ea1ad0..86d1ba53 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -1,7 +1,4 @@ -use daemon::{ - ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions, - ctrl_supported::SupportedFunctions, -}; +use daemon::{ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions, ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions}; use gumdrop::{Opt, Options}; use rog_dbus::AuraDbusClient; use rog_types::{ @@ -97,11 +94,11 @@ struct AniMeCommand { struct BiosCommand { #[options(help = "print help message")] help: bool, - #[options(meta = "", no_long, help = "toggle bios POST sound")] + #[options(meta = "", no_long, help = "set bios POST sound ")] post_sound_set: Option, #[options(no_long, help = "read bios POST sound")] post_sound_get: bool, - #[options(meta = "", no_long, help = "toggle GPU to/from dedicated mode")] + #[options(meta = "", no_long, help = "activate dGPU dedicated/G-Sync ")] dedicated_gfx_set: Option, #[options(no_long, help = "get GPU mode")] dedicated_gfx_get: bool, @@ -149,7 +146,7 @@ fn main() -> Result<(), Box> { match parsed.command { Some(CliCommand::LedMode(mode)) => handle_led_mode(&dbus, &supported.keyboard_led, &mode)?, Some(CliCommand::Profile(cmd)) => handle_profile(&dbus, &supported.fan_cpu_ctrl, &cmd)?, - Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, cmd)?, + Some(CliCommand::Graphics(cmd)) => do_gfx(&dbus, &supported.rog_bios_ctrl, cmd)?, Some(CliCommand::AniMe(cmd)) => { if (cmd.command.is_none() && cmd.boot.is_none() && cmd.turn.is_none()) || cmd.help { println!("Missing arg or command\n\n{}", cmd.self_usage()); @@ -173,43 +170,7 @@ fn main() -> Result<(), Box> { } } } - Some(CliCommand::Bios(cmd)) => { - if (cmd.dedicated_gfx_set.is_none() - && !cmd.dedicated_gfx_get - && cmd.post_sound_set.is_none() - && !cmd.post_sound_get) - || cmd.help - { - println!("Missing arg or command\n\n{}", cmd.self_usage()); - if let Some(lst) = cmd.self_command_list() { - println!("\n{}", lst); - } - } - - if let Some(opt) = cmd.post_sound_set { - dbus.proxies().rog_bios().set_post_sound(opt)?; - } - if cmd.post_sound_get { - let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 { - true - } else { - false - }; - println!("Bios POST sound on: {}", res); - } - if let Some(opt) = cmd.dedicated_gfx_set { - dbus.proxies().rog_bios().set_dedicated_gfx(opt)?; - } - if cmd.dedicated_gfx_get { - let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 { - true - } else { - false - }; - println!("Bios dedicated GPU on: {}", res); - println!("You must reboot your system to activate dedicated Nvidia mode"); - } - } + Some(CliCommand::Bios(cmd)) => handle_bios_option(&dbus, &supported.rog_bios_ctrl, &cmd)?, None => { if (!parsed.show_supported && parsed.kbd_bright.is_none() @@ -268,13 +229,19 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) { let commands: Vec = CliCommand::usage().lines().map(|s| s.to_string()).collect(); println!("\nCommands available"); for line in commands.iter().filter(|line| { - if line.contains("profile") && !supported.fan_cpu_ctrl.stock_fan_modes && !supported.fan_cpu_ctrl.fan_curve_set { + if line.contains("profile") + && !supported.fan_cpu_ctrl.stock_fan_modes + && !supported.fan_cpu_ctrl.fan_curve_set + { return false; } if line.contains("led-mode") && supported.keyboard_led.stock_led_modes.is_none() { return false; } - if line.contains("bios") && (!supported.rog_bios_ctrl.dedicated_gfx_toggle || !supported.rog_bios_ctrl.post_sound_toggle) { + if line.contains("bios") + && (!supported.rog_bios_ctrl.dedicated_gfx_toggle + || !supported.rog_bios_ctrl.post_sound_toggle) + { return false; } if line.contains("anime") && !supported.anime_ctrl.0 { @@ -294,14 +261,22 @@ fn print_supported_help(supported: &SupportedFunctions, parsed: &CLIStart) { } fn do_gfx( - dbus_client: &AuraDbusClient, + dbus: &AuraDbusClient, + supported: &RogBiosSupportedFunctions, command: GraphicsCommand, ) -> Result<(), Box> { - if command.mode.is_none() || command.help { + if command.mode.is_none() && !command.get && !command.pow && !command.force || command.help { println!("{}", command.self_usage()); } if let Some(mode) = command.mode { + if supported.dedicated_gfx_toggle { + if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 { + println!("You can not change modes until you turn dedicated/G-Sync off and reboot"); + std::process::exit(-1); + } + } + println!("Changing graphics modes..."); println!("If this takes longer than 30s, ctrl+c then check `journalctl -b -u asusd`"); @@ -310,19 +285,19 @@ fn do_gfx( "This will restart your display-manager. Please save all work!", "Setting graphics mode...", ) { - dbus_client.proxies().gfx().gfx_write_mode(mode.into())?; - let res = dbus_client.gfx_wait_changed()?; + dbus.proxies().gfx().gfx_write_mode(mode.into())?; + let res = dbus.gfx_wait_changed()?; println!("{}", res); std::process::exit(1) } std::process::exit(-1) } if command.get { - let res = dbus_client.proxies().gfx().gfx_get_mode()?; + let res = dbus.proxies().gfx().gfx_get_mode()?; println!("Current graphics mode: {}", res); } if command.pow { - let res = dbus_client.proxies().gfx().gfx_get_pwr()?; + let res = dbus.proxies().gfx().gfx_get_pwr()?; if res.contains("active") { println!("Current power status: {}", Red.paint(&format!("{}", res))); } else { @@ -359,10 +334,14 @@ fn handle_led_mode( println!("{}\n", mode.self_usage()); println!("Commands available"); - let commands: Vec = LedModeCommand::command_list().unwrap().lines().map(|s| s.to_string()).collect(); + let commands: Vec = LedModeCommand::command_list() + .unwrap() + .lines() + .map(|s| s.to_string()) + .collect(); for (_, command) in commands.iter().enumerate().filter(|(mode_num, _)| { if let Some(modes) = supported.stock_led_modes.as_ref() { - return modes.contains(&(*mode_num as u8)) + return modes.contains(&(*mode_num as u8)); } false }) { @@ -402,10 +381,14 @@ fn handle_profile( if !cmd.help { println!("Missing arg or command\n"); } - let usage: Vec = ProfileCommand::usage().lines().map(|s| s.to_string()).collect(); - for line in usage.iter().filter(|line| { - !(line.contains("--curve") && !supported.fan_curve_set) - }) { + let usage: Vec = ProfileCommand::usage() + .lines() + .map(|s| s.to_string()) + .collect(); + for line in usage + .iter() + .filter(|line| !(line.contains("--curve") && !supported.fan_curve_set)) + { println!("{}", line); } @@ -424,3 +407,64 @@ fn handle_profile( Ok(()) } + +fn handle_bios_option( + dbus: &AuraDbusClient, + supported: &RogBiosSupportedFunctions, + cmd: &BiosCommand, +) -> Result<(), Box> { + { + if (cmd.dedicated_gfx_set.is_none() + && !cmd.dedicated_gfx_get + && cmd.post_sound_set.is_none() + && !cmd.post_sound_get) + || cmd.help + { + println!("Missing arg or command\n"); + + let usage: Vec = BiosCommand::usage() + .lines() + .map(|s| s.to_string()) + .collect(); + + for line in usage + .iter() + .filter(|line| !(line.contains("sound") && !supported.post_sound_toggle) + || !(line.contains("GPU") && !supported.dedicated_gfx_toggle)) + { + println!("{}", line); + } + } + + if let Some(opt) = cmd.post_sound_set { + dbus.proxies().rog_bios().set_post_sound(opt)?; + } + if cmd.post_sound_get { + let res = if dbus.proxies().rog_bios().get_post_sound()? == 1 { + true + } else { + false + }; + println!("Bios POST sound on: {}", res); + } + if let Some(opt) = cmd.dedicated_gfx_set { + println!("Rebuilding initrd to include drivers"); + dbus.proxies().rog_bios().set_dedicated_gfx(opt)?; + println!("The mode change is not active until you reboot, on boot the bios will make the required change"); + if opt { + println!("NOTE: on reboot your display manager will be forced to use Nvidia drivers"); + } else { + println!("NOTE: after reboot you can then select regular graphics modes"); + } + } + if cmd.dedicated_gfx_get { + let res = if dbus.proxies().rog_bios().get_dedicated_gfx()? == 1 { + true + } else { + false + }; + println!("Bios dedicated GPU on: {}", res); + } + } + Ok(()) +} diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index bdbaac99..a972fa89 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "3.1.4" +version = "3.1.5" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] diff --git a/daemon/src/ctrl_gfx/error.rs b/daemon/src/ctrl_gfx/error.rs index 73bff37f..995867fb 100644 --- a/daemon/src/ctrl_gfx/error.rs +++ b/daemon/src/ctrl_gfx/error.rs @@ -1,5 +1,5 @@ -use std::error; use std::fmt; +use std::{error, process::ExitStatus}; use crate::error::RogError; @@ -7,7 +7,9 @@ use crate::error::RogError; pub enum GfxError { ParseVendor, Bus(String, std::io::Error), - DisplayManager(String), + DisplayManagerAction(String, ExitStatus), + DisplayManagerTimeout(String), + GsyncModeActive, } impl fmt::Display for GfxError { @@ -16,7 +18,13 @@ impl fmt::Display for GfxError { match self { GfxError::ParseVendor => write!(f, "Could not parse vendor name"), GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error), - GfxError::DisplayManager(detail) => write!(f, "Display manager: {}", detail), + GfxError::DisplayManagerAction(action, status) => { + write!(f, "Display-manager action {} failed: {}", action, status) + } + GfxError::DisplayManagerTimeout(state) => { + write!(f, "Timed out waiting for display-manager {} state", state) + } + GfxError::GsyncModeActive => write!(f, "Can not switch gfx modes when dedicated/G-Sync mode is active"), } } } diff --git a/daemon/src/ctrl_gfx/gfx.rs b/daemon/src/ctrl_gfx/gfx.rs index d9dceb78..fcdcf8b1 100644 --- a/daemon/src/ctrl_gfx/gfx.rs +++ b/daemon/src/ctrl_gfx/gfx.rs @@ -1,5 +1,6 @@ use ctrl_gfx::error::GfxError; use ctrl_gfx::*; +use ctrl_rog_bios::CtrlRogBios; use log::{error, info, warn}; use rog_types::gfx_vendors::GfxVendors; use std::iter::FromIterator; @@ -260,8 +261,25 @@ impl CtrlGraphics { Ok(()) } + fn log_uses_of_nvidia() { + // lsof /dev/nvidia* + let mut cmd = Command::new("lsof"); + cmd.arg("/dev/nvidia*"); + + match cmd.output() { + Ok(output) => { + if !output.status.success() { + error!("Failed to list uses of nvidia devices: {}", String::from_utf8_lossy(&output.stderr)); + } else if output.status.success() { + warn!("{}", String::from_utf8_lossy(&output.stdout)); + } + } + Err(err) => error!("Failed to list uses of nvidia devices: {}", err), + } + } + fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> { - let mut cmd= Command::new(action); + let mut cmd = Command::new(action); cmd.arg(driver); let mut count = 0; @@ -270,28 +288,41 @@ impl CtrlGraphics { if count > MAX_TRIES { let msg = format!("{} {} failed for unknown reason", action, driver); error!("{}", msg); - return Ok(()) //Err(RogError::Modprobe(msg)); + return Ok(()); //Err(RogError::Modprobe(msg)); } let output = cmd .output() .map_err(|err| RogError::Command(format!("{:?}", cmd), err))?; if !output.status.success() { - if output.stderr.ends_with("is not currently loaded\n".as_bytes()) { - return Ok(()) + if output + .stderr + .ends_with("is not currently loaded\n".as_bytes()) + { + return Ok(()); } if output.stderr.ends_with("Permission denied\n".as_bytes()) { - let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr)); + let msg = format!( + "{} {} failed: {:?}", + action, + driver, + String::from_utf8_lossy(&output.stderr) + ); warn!("{}", msg); warn!("It may be safe to ignore the above error, run `lsmod |grep nvidia` to confirm modules loaded"); - return Ok(()) + return Ok(()); } if count >= MAX_TRIES { - let msg = format!("{} {} failed: {:?}", action, driver, String::from_utf8_lossy(&output.stderr)); + let msg = format!( + "{} {} failed: {:?}", + action, + driver, + String::from_utf8_lossy(&output.stderr) + ); return Err(RogError::Modprobe(msg)); } } else if output.status.success() { - return Ok(()) + return Ok(()); } count += 1; @@ -312,7 +343,7 @@ impl CtrlGraphics { "systemctl {} {} failed: {:?}", action, DISPLAY_MANAGER, status ); - return Err(GfxError::DisplayManager(msg).into()); + return Err(GfxError::DisplayManagerAction(msg, status).into()); } Ok(()) } @@ -334,9 +365,7 @@ impl CtrlGraphics { std::thread::sleep(std::time::Duration::from_millis(500)); count += 1; } - return Err( - GfxError::DisplayManager(format!("display-manager timed out waiting for {} state", state).into()).into(), - ); + return Err(GfxError::DisplayManagerTimeout(state.into()).into()); } pub fn do_vendor_tasks(&mut self, vendor: GfxVendors) -> Result<(), RogError> { @@ -351,7 +380,10 @@ impl CtrlGraphics { match vendor { GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => { for driver in NVIDIA_DRIVERS.iter() { - Self::do_driver_action(driver, "modprobe")?; + Self::do_driver_action(driver, "modprobe").map_err(|err| { + Self::log_uses_of_nvidia(); + err + })?; } } // TODO: compute mode, needs different setup @@ -372,11 +404,38 @@ impl CtrlGraphics { /// /// Will stop and start display manager without warning pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result { + if let Ok(gsync) = CtrlRogBios::get_gfx_mode() { + if gsync == 1{ + return Err(GfxError::GsyncModeActive.into()); + } + } + Self::do_display_manager_action("stop")?; - Self::wait_display_manager_state("inactive")?; + match Self::wait_display_manager_state("inactive") { + Ok(_) => info!("display-manager stopped"), + Err(err) => { + warn!("{}", err); + warn!("Retry stop display manager"); + Self::do_display_manager_action("stop")?; + Self::wait_display_manager_state("inactive")?; + } + } + self.do_vendor_tasks(vendor)?; + Self::do_display_manager_action("start")?; + match Self::wait_display_manager_state("active") { + Ok(_) => info!("display-manager started"), + Err(err) => { + warn!("{}", err); + warn!("Retry start display manager"); + Self::do_display_manager_action("restart")?; + Self::wait_display_manager_state("active")?; + } + } + if Self::wait_display_manager_state("active").is_err() { + error!("display-manager failed to start normally, attempting restart"); Self::do_display_manager_action("restart")?; } Self::wait_display_manager_state("active")?; diff --git a/daemon/src/ctrl_gfx/mod.rs b/daemon/src/ctrl_gfx/mod.rs index 0b293766..18d08f00 100644 --- a/daemon/src/ctrl_gfx/mod.rs +++ b/daemon/src/ctrl_gfx/mod.rs @@ -11,6 +11,8 @@ const DISPLAY_MANAGER: &str = "display-manager.service"; const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf"; static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd +# If you have issues with i2c_nvidia_gpu, copy the 2 lines below to a +# new blacklist file and uncomment #blacklist i2c_nvidia_gpu #alias i2c_nvidia_gpu off blacklist nouveau diff --git a/daemon/src/ctrl_rog_bios.rs b/daemon/src/ctrl_rog_bios.rs index 40b5823f..9ff1df0c 100644 --- a/daemon/src/ctrl_rog_bios.rs +++ b/daemon/src/ctrl_rog_bios.rs @@ -136,9 +136,7 @@ impl CtrlRogBios { } } - Ok(CtrlRogBios { - _config: config, - }) + Ok(CtrlRogBios { _config: config }) } fn set_path_mutable(path: &str) -> Result<(), RogError> { @@ -271,6 +269,7 @@ impl CtrlRogBios { } else if Path::new(DRACUT_PATH).exists() { let mut cmd = Command::new("dracut"); cmd.arg("-f"); + cmd.arg("-q"); initfs_cmd = Some(cmd); info!("Using initramfs update command 'dracut'"); } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 139ad676..49826d1c 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -111,8 +111,7 @@ fn start_daemon() -> Result<(), Box> { if let Ok(ded) = CtrlRogBios::get_gfx_mode() { if let Ok(vendor) = ctrl.get_gfx_mode() { if ded == 1 && vendor != GfxVendors::Nvidia { - error!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); - error!("You must reboot to enable Nvidia driver"); + warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode"); ctrl.do_vendor_tasks(GfxVendors::Nvidia)?; } else if ded == 0 { info!("Dedicated GFX toggle is off"); diff --git a/rog-types/src/profile.rs b/rog-types/src/profile.rs index b6dffe03..2450d8c4 100644 --- a/rog-types/src/profile.rs +++ b/rog-types/src/profile.rs @@ -90,7 +90,11 @@ pub struct ProfileCommand { #[options(meta = "", help = "")] pub fan_preset: Option, - #[options(meta = "", parse(try_from_str = "parse_fan_curve"), help = "set fan curve")] + #[options( + meta = "", + parse(try_from_str = "parse_fan_curve"), + help = "set fan curve" + )] pub curve: Option, #[options(free)] pub profile: Option,