VFIO mode enabled

This commit is contained in:
Luke D Jones
2021-03-20 23:26:03 +13:00
parent 45ab568f7a
commit 538e111e78
15 changed files with 240 additions and 179 deletions

View File

@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Refactor keyboard LED handling - Refactor keyboard LED handling
- Added --list for profiles (Thanks @aqez) - Added --list for profiles (Thanks @aqez)
- Added --remove for profiles (Thanks @aqez) - Added --remove for profiles (Thanks @aqez)
- Added a graphics mode: vfio. This attaches Nvidia devices to vfio module.
### Broken ### Broken
- Per-key LED modes, which need thinking about how to go ahead with for future - Per-key LED modes, which need thinking about how to go ahead with for future

View File

@@ -30,7 +30,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if let Some(notif) = last_gfx_notif.take() { if let Some(notif) = last_gfx_notif.take() {
notif.close(); notif.close();
} }
let x = do_notif(&format!("Graphics mode changed to {}", vendor))?; let x = do_notif(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))?;
last_gfx_notif = Some(x); last_gfx_notif = Some(x);
} }
} }

View File

@@ -1,8 +1,8 @@
use gumdrop::Options;
use rog_types::{ use rog_types::{
aura_modes::{Colour, Direction, Speed, AuraEffect, AuraModeNum, AuraZone}, aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
error::AuraError, error::AuraError,
}; };
use gumdrop::Options;
use std::str::FromStr; use std::str::FromStr;
#[derive(Options)] #[derive(Options)]
@@ -165,7 +165,6 @@ impl Default for SetAuraBuiltin {
} }
} }
impl From<&SingleColour> for AuraEffect { impl From<&SingleColour> for AuraEffect {
fn from(aura: &SingleColour) -> Self { fn from(aura: &SingleColour) -> Self {
Self { Self {
@@ -302,7 +301,7 @@ impl From<&SetAuraBuiltin> for Vec<AuraEffect> {
zones[3].mode = AuraModeNum::Static; zones[3].mode = AuraModeNum::Static;
zones[3].zone = AuraZone::Four; zones[3].zone = AuraZone::Four;
zones[3].colour1 = data.colour4; zones[3].colour1 = data.colour4;
}, }
SetAuraBuiltin::MultiBreathe(data) => { SetAuraBuiltin::MultiBreathe(data) => {
zones[0].mode = AuraModeNum::Breathe; zones[0].mode = AuraModeNum::Breathe;
zones[0].zone = AuraZone::One; zones[0].zone = AuraZone::One;
@@ -324,7 +323,7 @@ impl From<&SetAuraBuiltin> for Vec<AuraEffect> {
zones[3].colour1 = data.colour4; zones[3].colour1 = data.colour4;
zones[3].speed = data.speed; zones[3].speed = data.speed;
} }
_ => {}, _ => {}
} }
zones zones
} }

View File

@@ -1,5 +1,6 @@
mod aura_cli; mod aura_cli;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
use daemon::{ use daemon::{
ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions, ctrl_fan_cpu::FanCpuSupportedFunctions, ctrl_leds::LedSupportedFunctions,
ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions, ctrl_rog_bios::RogBiosSupportedFunctions, ctrl_supported::SupportedFunctions,
@@ -16,7 +17,6 @@ use rog_types::{
use std::env::args; use std::env::args;
use yansi_term::Colour::Green; use yansi_term::Colour::Green;
use yansi_term::Colour::Red; use yansi_term::Colour::Red;
use crate::aura_cli::{LedBrightness, SetAuraBuiltin};
#[derive(Default, Options)] #[derive(Default, Options)]
struct CLIStart { struct CLIStart {
@@ -286,19 +286,24 @@ fn do_gfx(
std::process::exit(-1); std::process::exit(-1);
} }
println!( println!("If anything fails check `journalctl -b -u asusd`\n");
"Your display-manager will restart in requested mode when all users are logged out"
);
println!("If anything fails check `journalctl -b -u asusd`");
dbus.proxies().gfx().gfx_write_mode(mode.into())?; dbus.proxies().gfx().gfx_write_mode(&mode).map_err(|err|{
println!("Graphics mode change error. You may be in an invalid state.");
println!("Check mode with `asusctl graphics -g` and switch to opposite\nmode to correct it, e.g: if integrated, switch to hybrid, or if nvidia, switch to integrated.\n");
err
})?;
let res = dbus.gfx_wait_changed()?; let res = dbus.gfx_wait_changed()?;
println!("{}", res); println!(
"Graphics mode changed to {}. User action required is: {}",
<&str>::from(mode),
<&str>::from(&res)
);
std::process::exit(0) std::process::exit(0)
} }
if command.get { if command.get {
let res = dbus.proxies().gfx().gfx_get_mode()?; let res = dbus.proxies().gfx().gfx_get_mode()?;
println!("Current graphics mode: {}", res); println!("Current graphics mode: {}", <&str>::from(res));
} }
if command.pow { if command.pow {
let res = dbus.proxies().gfx().gfx_get_pwr()?; let res = dbus.proxies().gfx().gfx_get_pwr()?;
@@ -361,9 +366,7 @@ fn handle_led_mode(
SetAuraBuiltin::MultiStatic(_) | SetAuraBuiltin::MultiBreathe(_) => { SetAuraBuiltin::MultiStatic(_) | SetAuraBuiltin::MultiBreathe(_) => {
let zones = <Vec<AuraEffect>>::from(mode); let zones = <Vec<AuraEffect>>::from(mode);
for eff in zones { for eff in zones {
dbus.proxies() dbus.proxies().led().set_led_mode(&eff)?
.led()
.set_led_mode(&eff)?
} }
} }
_ => dbus _ => dbus

View File

@@ -160,7 +160,9 @@ impl DbusFanAndCpu {
} }
if cfg.active_profile == *profile { if cfg.active_profile == *profile {
return Err(Error::Failed("Cannot delete the active profile".to_string())); return Err(Error::Failed(
"Cannot delete the active profile".to_string(),
));
} }
cfg.power_profiles.remove(profile); cfg.power_profiles.remove(profile);

View File

@@ -6,11 +6,11 @@ use logind_zbus::{
types::{SessionClass, SessionInfo, SessionType}, types::{SessionClass, SessionInfo, SessionType},
ManagerProxy, SessionProxy, ManagerProxy, SessionProxy,
}; };
use rog_types::gfx_vendors::GfxVendors; use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::mpsc;
use std::{io::Write, ops::Add, path::Path, time::Instant}; use std::{io::Write, ops::Add, path::Path, time::Instant};
use std::{iter::FromIterator, thread::JoinHandle}; use std::{iter::FromIterator, thread::JoinHandle};
use std::{process::Command, thread::sleep, time::Duration}; use std::{process::Command, thread::sleep, time::Duration};
use std::{str::FromStr, sync::mpsc};
use std::{sync::Arc, sync::Mutex}; use std::{sync::Arc, sync::Mutex};
use sysfs_class::{PciDevice, SysClass}; use sysfs_class::{PciDevice, SysClass};
use system::{GraphicsDevice, PciBus}; use system::{GraphicsDevice, PciBus};
@@ -32,44 +32,44 @@ pub struct CtrlGraphics {
} }
trait Dbus { trait Dbus {
fn vendor(&self) -> String; fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
fn power(&self) -> String; fn power(&self) -> String;
fn set_vendor(&mut self, vendor: String); fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>; fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
fn notify_action(&self, action: &str) -> zbus::Result<()>; fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
} }
#[dbus_interface(name = "org.asuslinux.Daemon")] #[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics { impl Dbus for CtrlGraphics {
fn vendor(&self) -> String { fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
self.get_gfx_mode() self.get_gfx_mode().map_err(|err| {
.map(|gfx| (<&str>::from(gfx)).into()) error!("GFX: {}", err);
.unwrap_or_else(|err| format!("Get vendor failed: {}", err)) zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
})
} }
fn power(&self) -> String { fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err)) Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
} }
fn set_vendor(&mut self, vendor: String) { fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
if let Ok(tmp) = GfxVendors::from_str(&vendor) { info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
info!("GFX: Switching gfx mode to {}", vendor); let msg = self.set_gfx_config(vendor).map_err(|err| {
let msg = self.set_gfx_config(tmp).unwrap_or_else(|err| { error!("GFX: {}", err);
error!("GFX: {}", err); zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
format!("Failed: {}", err.to_string()) })?;
}); self.notify_gfx(&vendor)
self.notify_gfx(&vendor) .unwrap_or_else(|err| warn!("GFX: {}", err));
.unwrap_or_else(|err| warn!("GFX: {}", err)); self.notify_action(&msg)
self.notify_action(&msg) .unwrap_or_else(|err| warn!("GFX: {}", err));
.unwrap_or_else(|err| warn!("GFX: {}", err)); Ok(msg)
}
} }
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()> {} fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
#[dbus_interface(signal)] #[dbus_interface(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()> {} fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
} }
impl ZbusAdd for CtrlGraphics { impl ZbusAdd for CtrlGraphics {
@@ -163,6 +163,7 @@ impl CtrlGraphics {
self.nvidia.clone() self.nvidia.clone()
} }
/// Save the selected `Vendor` mode to config
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) { fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
if let Ok(mut config) = config.lock() { if let Ok(mut config) = config.lock() {
config.gfx_mode = vendor; config.gfx_mode = vendor;
@@ -238,8 +239,40 @@ impl CtrlGraphics {
Ok(()) Ok(())
} }
fn write_modprobe_conf(content: &[u8]) -> Result<(), RogError> { fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
let mut vifo = MODPROBE_VFIO.to_vec();
for (d_count, dev) in devices.iter().enumerate() {
for (f_count, func) in dev.functions().iter().enumerate() {
let vendor = func.vendor().unwrap();
let device = func.device().unwrap();
unsafe {
vifo.append(format!("{:x}", vendor).as_mut_vec());
}
vifo.append(&mut vec![b':']);
unsafe {
vifo.append(format!("{:x}", device).as_mut_vec());
}
if f_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
if d_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
let mut conf = MODPROBE_INTEGRATED.to_vec();
conf.append(&mut vifo);
conf
}
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
info!("GFX: Writing {}", MODPROBE_PATH); info!("GFX: Writing {}", MODPROBE_PATH);
let content = match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => MODPROBE_BASE.to_vec(),
GfxVendors::Vfio => Self::get_vfio_conf(devices),
// GfxVendors::Compute => {}
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
};
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.create(true) .create(true)
@@ -248,7 +281,7 @@ impl CtrlGraphics {
.open(MODPROBE_PATH) .open(MODPROBE_PATH)
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?; .map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
file.write_all(content) file.write_all(&content)
.and_then(|_| file.sync_all()) .and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?; .map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
@@ -258,34 +291,16 @@ impl CtrlGraphics {
fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> { fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> {
// Unbind NVIDIA graphics devices and their functions // Unbind NVIDIA graphics devices and their functions
let unbinds = devices.iter().map(|dev| dev.unbind()); let unbinds = devices.iter().map(|dev| dev.unbind());
// Remove NVIDIA graphics devices and their functions // Remove NVIDIA graphics devices and their functions
let removes = devices.iter().map(|dev| dev.remove()); let removes = devices.iter().map(|dev| dev.remove());
Result::from_iter(unbinds.chain(removes)) Result::from_iter(unbinds.chain(removes))
.map_err(|err| RogError::Command("device unbind error".into(), err))?; .map_err(|err| RogError::Command("device unbind error".into(), err))
Ok(())
} }
fn log_uses_of_nvidia() { fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> {
// lsof /dev/nvidia* let unbinds = devices.iter().map(|dev| dev.unbind());
let mut cmd = Command::new("lsof"); Result::from_iter(unbinds)
cmd.arg("/dev/nvidia*"); .map_err(|err| RogError::Command("device unbind error".into(), err))
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!("GFX: {}", String::from_utf8_lossy(&output.stdout));
}
}
Err(err) => error!("GFX: Failed to list uses of nvidia devices: {}", err),
}
} }
fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> { fn do_driver_action(driver: &str, action: &str) -> Result<(), RogError> {
@@ -312,14 +327,13 @@ impl CtrlGraphics {
return Ok(()); return Ok(());
} }
if output.stderr.ends_with("Permission denied\n".as_bytes()) { if output.stderr.ends_with("Permission denied\n".as_bytes()) {
let msg = format!( warn!(
"{} {} failed: {:?}", "{} {} failed: {:?}",
action, action,
driver, driver,
String::from_utf8_lossy(&output.stderr) String::from_utf8_lossy(&output.stderr)
); );
warn!("GFX: {}", msg); warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
warn!("GFX: 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 { if count >= MAX_TRIES {
@@ -378,6 +392,20 @@ impl CtrlGraphics {
Err(GfxError::DisplayManagerTimeout(state.into()).into()) Err(GfxError::DisplayManagerTimeout(state.into()).into())
} }
/// Determine if we need to logout/thread. Integrated<->Vfio mode does not
/// require logout.
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
if let Ok(config) = self.config.lock() {
let current = config.gfx_mode;
if matches!(current, GfxVendors::Integrated | GfxVendors::Vfio)
&& matches!(vendor, GfxVendors::Integrated | GfxVendors::Vfio)
{
return GfxRequiredUserAction::None;
}
}
GfxRequiredUserAction::Logout
}
/// Write the config changes and add/remove drivers and devices depending /// Write the config changes and add/remove drivers and devices depending
/// on selected mode: /// on selected mode:
/// ///
@@ -387,35 +415,40 @@ impl CtrlGraphics {
/// - rescan for devices /// - rescan for devices
/// + add drivers /// + add drivers
/// + or remove drivers and devices /// + or remove drivers and devices
///
/// The daemon needs direct access to this function when it detects that the
pub fn do_vendor_tasks( pub fn do_vendor_tasks(
vendor: GfxVendors, vendor: GfxVendors,
devices: &[GraphicsDevice], devices: &[GraphicsDevice],
bus: &PciBus, bus: &PciBus,
) -> Result<(), RogError> { ) -> Result<(), RogError> {
// Rescan before doing remove or add drivers
bus.rescan()?;
//
Self::write_xorg_conf(vendor)?; Self::write_xorg_conf(vendor)?;
// Write different modprobe to enable boot control to work // Write different modprobe to enable boot control to work
match vendor { Self::write_modprobe_conf(vendor, devices)?;
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
Self::write_modprobe_conf(MODPROBE_BASE)?
}
// GfxVendors::Compute => {}
GfxVendors::Integrated => Self::write_modprobe_conf(MODPROBE_INTEGRATED)?,
}
// Rescan before doing remove or add drivers
bus.rescan()
.map_err(|err| GfxError::Bus("bus rescan error".into(), err))?;
match vendor { match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => { GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
for driver in NVIDIA_DRIVERS.iter() { for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "modprobe").map_err(|err| { Self::do_driver_action(driver, "modprobe")?;
Self::log_uses_of_nvidia();
err
})?;
} }
} }
GfxVendors::Vfio => {
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
Self::unbind_only(&devices)?;
Self::do_driver_action("vfio-pci", "modprobe")?;
}
GfxVendors::Integrated => { GfxVendors::Integrated => {
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
for driver in NVIDIA_DRIVERS.iter() { for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?; Self::do_driver_action(driver, "rmmod")?;
} }
@@ -426,7 +459,7 @@ impl CtrlGraphics {
Ok(()) Ok(())
} }
fn graphical_session_active( fn graphical_session_alive(
connection: &Connection, connection: &Connection,
sessions: &[SessionInfo], sessions: &[SessionInfo],
) -> Result<bool, RogError> { ) -> Result<bool, RogError> {
@@ -435,9 +468,9 @@ impl CtrlGraphics {
if session_proxy.get_class()? == SessionClass::User { if session_proxy.get_class()? == SessionClass::User {
match session_proxy.get_type()? { match session_proxy.get_type()? {
SessionType::X11 | SessionType::Wayland | SessionType::MIR => { SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
if session_proxy.get_active()? { //if session_proxy.get_active()? {
return Ok(true); return Ok(true);
} //}
} }
_ => {} _ => {}
} }
@@ -452,6 +485,7 @@ impl CtrlGraphics {
devices: Vec<GraphicsDevice>, devices: Vec<GraphicsDevice>,
bus: PciBus, bus: PciBus,
thread_stop: mpsc::Receiver<bool>, thread_stop: mpsc::Receiver<bool>,
config: Arc<Mutex<Config>>,
) -> Result<String, RogError> { ) -> Result<String, RogError> {
info!("GFX: display-manager thread started"); info!("GFX: display-manager thread started");
@@ -470,7 +504,7 @@ impl CtrlGraphics {
sessions = tmp; sessions = tmp;
} }
if !Self::graphical_session_active(&connection, &sessions)? { if !Self::graphical_session_alive(&connection, &sessions)? {
break; break;
} }
@@ -510,6 +544,8 @@ impl CtrlGraphics {
Self::do_display_manager_action("restart")?; Self::do_display_manager_action("restart")?;
Self::wait_display_manager_state("active")?; Self::wait_display_manager_state("active")?;
} }
// Save selected mode in case of reboot
Self::save_gfx_mode(vendor, config);
info!("GFX: display-manager started"); info!("GFX: display-manager started");
let v: &str = vendor.into(); let v: &str = vendor.into();
@@ -517,18 +553,7 @@ impl CtrlGraphics {
Ok(format!("Graphics mode changed to {} successfully", v)) Ok(format!("Graphics mode changed to {} successfully", v))
} }
/// Initiates a mode change by starting a thread that will wait until all fn cancel_thread(&self) {
/// graphical sessions are exited before performing the tasks required
/// to switch modes.
///
/// For manually calling (not on boot/startup) via dbus
pub fn set_gfx_config(&mut self, vendor: GfxVendors) -> Result<String, RogError> {
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
if gsync == 1 {
return Err(GfxError::GsyncModeActive.into());
}
}
if let Ok(lock) = self.thread_kill.lock() { if let Ok(lock) = self.thread_kill.lock() {
if let Some(tx) = lock.as_ref() { if let Some(tx) = lock.as_ref() {
// Cancel the running thread // Cancel the running thread
@@ -540,7 +565,11 @@ impl CtrlGraphics {
.ok(); .ok();
} }
} }
}
/// The thread is used only in cases where a logout is required
fn setup_thread(&mut self, vendor: GfxVendors) {
let config = self.config.clone();
let devices = self.nvidia.clone(); let devices = self.nvidia.clone();
let bus = self.bus.clone(); let bus = self.bus.clone();
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@@ -549,11 +578,8 @@ impl CtrlGraphics {
} }
let killer = self.thread_kill.clone(); let killer = self.thread_kill.clone();
// Save selected mode in case of reboot
Self::save_gfx_mode(vendor, self.config.clone());
let _join: JoinHandle<()> = std::thread::spawn(move || { let _join: JoinHandle<()> = std::thread::spawn(move || {
Self::fire_starter(vendor, devices, bus, rx) Self::fire_starter(vendor, devices, bus, rx, config)
.map_err(|err| { .map_err(|err| {
error!("GFX: {}", err); error!("GFX: {}", err);
}) })
@@ -563,28 +589,42 @@ impl CtrlGraphics {
*lock = None; *lock = None;
} }
}); });
// TODO: undo if failed? Save last mode, catch errors...
let v: &str = vendor.into();
Ok(format!("Graphics mode changed to {} successfully", v))
} }
// if CtrlRogBios::has_dedicated_gfx_toggle() { /// Initiates a mode change by starting a thread that will wait until all
// if let Ok(config) = self.config.clone().try_lock() { /// graphical sessions are exited before performing the tasks required
// // Switch to dedicated if config says to do so /// to switch modes.
// if config.gfx_nv_mode_is_dedicated && vendor == GfxVendors::Nvidia { ///
// CtrlRogBios::set_gfx_mode(true) /// For manually calling (not on boot/startup) via dbus
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err)); pub fn set_gfx_config(
// } else if let Ok(ded) = CtrlRogBios::get_gfx_mode() { &mut self,
// // otherwise if switching to non-Nvidia mode turn off dedicated mode vendor: GfxVendors,
// if ded == 1 && vendor != GfxVendors::Nvidia { ) -> Result<GfxRequiredUserAction, RogError> {
// CtrlRogBios::set_gfx_mode(false) if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
// .unwrap_or_else(|err| warn!("GFX: Gfx controller: {}", err)); if gsync == 1 {
// } return Err(GfxError::GsyncModeActive.into());
// } }
// } }
// } // Must always cancel any thread running
self.cancel_thread();
// determine which method we need here
let action_required = self.logout_required(vendor);
if matches!(action_required, GfxRequiredUserAction::Logout) {
// Yeah need the thread to check if all users are logged out
info!("GFX: mode change requires a logout to complete");
self.setup_thread(vendor);
} else {
// Okay cool, we can switch on/off vfio
info!("GFX: mode change does not require logout");
let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
}
// TODO: undo if failed? Save last mode, catch errors...
Ok(action_required)
}
/// Used only on boot to set correct mode
fn auto_power(&mut self) -> Result<(), RogError> { fn auto_power(&mut self) -> Result<(), RogError> {
let vendor = self.get_gfx_mode()?; let vendor = self.get_gfx_mode()?;
let devices = self.nvidia.clone(); let devices = self.nvidia.clone();

View File

@@ -6,6 +6,14 @@ pub mod system;
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"]; const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
const VFIO_DRIVERS: [&str; 5] = [
"vfio-pci",
"vfio_iommu_type1",
"vfio_virqfd",
"vfio_mdev",
"vfio",
];
const DISPLAY_MANAGER: &str = "display-manager.service"; const DISPLAY_MANAGER: &str = "display-manager.service";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf"; const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
@@ -30,6 +38,8 @@ blacklist nouveau
alias nouveau off alias nouveau off
"#; "#;
static MODPROBE_VFIO: &[u8] = br#"options vfio-pci ids="#;
const XORG_FILE: &str = "90-nvidia-primary.conf"; const XORG_FILE: &str = "90-nvidia-primary.conf";
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/"; const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";

View File

@@ -72,6 +72,10 @@ impl GraphicsDevice {
self.functions.iter().any(|func| func.path().exists()) self.functions.iter().any(|func| func.path().exists())
} }
pub fn functions(&self) -> &[PciDevice] {
&self.functions
}
pub fn unbind(&self) -> Result<(), std::io::Error> { pub fn unbind(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() { for func in self.functions.iter() {
if func.path().exists() { if func.path().exists() {

View File

@@ -28,6 +28,7 @@ pub enum RogError {
Initramfs(String), Initramfs(String),
Modprobe(String), Modprobe(String),
Command(String, std::io::Error), Command(String, std::io::Error),
Io(std::io::Error),
Zbus(zbus::Error), Zbus(zbus::Error),
} }
@@ -55,6 +56,7 @@ impl fmt::Display for RogError {
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error), RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail), RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
} }
} }
@@ -87,3 +89,9 @@ impl From<zbus::Error> for RogError {
RogError::Zbus(err) RogError::Zbus(err)
} }
} }
impl From<std::io::Error> for RogError {
fn from(err: std::io::Error) -> Self {
RogError::Io(err)
}
}

View File

@@ -11,7 +11,10 @@ pub mod zbus_profile;
pub mod zbus_rogbios; pub mod zbus_rogbios;
pub mod zbus_supported; pub mod zbus_supported;
use rog_types::aura_modes::AuraEffect; use rog_types::{
aura_modes::AuraEffect,
gfx_vendors::{GfxRequiredUserAction, GfxVendors},
};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use zbus::{Connection, Result, SignalReceiver}; use zbus::{Connection, Result, SignalReceiver};
@@ -86,8 +89,8 @@ impl<'a> DbusProxies<'a> {
// Signals separated out // Signals separated out
pub struct Signals { pub struct Signals {
pub gfx_vendor: Arc<Mutex<Option<String>>>, pub gfx_vendor: Arc<Mutex<Option<GfxVendors>>>,
pub gfx_action: Arc<Mutex<Option<String>>>, pub gfx_action: Arc<Mutex<Option<GfxRequiredUserAction>>>,
pub profile: Arc<Mutex<Option<String>>>, pub profile: Arc<Mutex<Option<String>>>,
pub led_mode: Arc<Mutex<Option<AuraEffect>>>, pub led_mode: Arc<Mutex<Option<AuraEffect>>>,
pub charge: Arc<Mutex<Option<u8>>>, pub charge: Arc<Mutex<Option<u8>>>,
@@ -151,13 +154,13 @@ impl<'a> AuraDbusClient<'a> {
/* /*
* GFX * GFX
*/ */
pub fn gfx_wait_changed(&self) -> Result<String> { pub fn gfx_wait_changed(&self) -> Result<GfxRequiredUserAction> {
loop { loop {
if let Ok(res) = self.proxies.gfx.proxy().next_signal() { if let Ok(res) = self.proxies.gfx.proxy().next_signal() {
if res.is_none() { if res.is_none() {
if let Ok(lock) = self.signals.gfx_action.lock() { if let Ok(lock) = self.signals.gfx_action.lock() {
if let Some(stuff) = lock.as_ref() { if let Some(stuff) = lock.as_ref() {
return Ok(stuff.to_string()); return Ok(*stuff);
} }
} }
// return Ok("Failed for unknown reason".to_owned()); // return Ok("Failed for unknown reason".to_owned());

View File

@@ -21,6 +21,7 @@
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use zbus::{dbus_proxy, Connection, Result}; use zbus::{dbus_proxy, Connection, Result};
#[dbus_proxy( #[dbus_proxy(
@@ -32,18 +33,18 @@ trait Daemon {
fn power(&self) -> zbus::Result<String>; fn power(&self) -> zbus::Result<String>;
/// SetVendor method /// SetVendor method
fn set_vendor(&self, vendor: &str) -> zbus::Result<()>; fn set_vendor(&self, vendor: &GfxVendors) -> zbus::Result<GfxRequiredUserAction>;
/// Vendor method /// Vendor method
fn vendor(&self) -> zbus::Result<String>; fn vendor(&self) -> zbus::Result<GfxVendors>;
/// NotifyAction signal /// NotifyAction signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_action(&self, action: &str) -> zbus::Result<()>; fn notify_action(&self, action: GfxRequiredUserAction) -> zbus::Result<()>;
/// NotifyGfx signal /// NotifyGfx signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_gfx(&self, vendor: &str) -> zbus::Result<()>; fn notify_gfx(&self, vendor: GfxVendors) -> zbus::Result<()>;
} }
pub struct GfxProxy<'a>(DaemonProxy<'a>); pub struct GfxProxy<'a>(DaemonProxy<'a>);
@@ -64,33 +65,36 @@ impl<'a> GfxProxy<'a> {
} }
#[inline] #[inline]
pub fn gfx_get_mode(&self) -> Result<String> { pub fn gfx_get_mode(&self) -> Result<GfxVendors> {
self.0.vendor() self.0.vendor()
} }
#[inline] #[inline]
pub fn gfx_write_mode(&self, vendor: &str) -> Result<()> { pub fn gfx_write_mode(&self, vendor: &GfxVendors) -> Result<GfxRequiredUserAction> {
self.0.set_vendor(vendor) self.0.set_vendor(vendor)
} }
#[inline] #[inline]
pub fn connect_notify_action( pub fn connect_notify_action(
&self, &self,
action: Arc<Mutex<Option<String>>>, action: Arc<Mutex<Option<GfxRequiredUserAction>>>,
) -> zbus::fdo::Result<()> { ) -> zbus::fdo::Result<()> {
self.0.connect_notify_action(move |data| { self.0.connect_notify_action(move |data| {
if let Ok(mut lock) = action.lock() { if let Ok(mut lock) = action.lock() {
*lock = Some(data.to_owned()); *lock = Some(data);
} }
Ok(()) Ok(())
}) })
} }
#[inline] #[inline]
pub fn connect_notify_gfx(&self, vendor: Arc<Mutex<Option<String>>>) -> zbus::fdo::Result<()> { pub fn connect_notify_gfx(
&self,
vendor: Arc<Mutex<Option<GfxVendors>>>,
) -> zbus::fdo::Result<()> {
self.0.connect_notify_gfx(move |data| { self.0.connect_notify_gfx(move |data| {
if let Ok(mut lock) = vendor.lock() { if let Ok(mut lock) = vendor.lock() {
*lock = Some(data.to_owned()); *lock = Some(data);
} }
Ok(()) Ok(())
}) })

View File

@@ -45,7 +45,7 @@ trait Daemon {
fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>; fn set_led_mode(&self, effect: &AuraEffect) -> zbus::Result<()>;
/// NotifyLed signal /// NotifyLed signal
/// NotifyLed signal /// NotifyLed signal
#[dbus_proxy(signal)] #[dbus_proxy(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>; fn notify_led(&self, data: &str) -> zbus::Result<()>;

View File

@@ -4,8 +4,8 @@
// static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e // static LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
// static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; // static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
use crate::LED_MSG_LEN;
use crate::error::AuraError; use crate::error::AuraError;
use crate::LED_MSG_LEN;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use zvariant_derive::Type; use zvariant_derive::Type;

View File

@@ -1,6 +1,4 @@
use crate::{ use crate::error::AuraError;
error::AuraError,
};
use gumdrop::Options; use gumdrop::Options;
use std::str::FromStr; use std::str::FromStr;

View File

@@ -1,12 +1,14 @@
use crate::error::GraphicsError; use crate::error::GraphicsError;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use zvariant_derive::Type;
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] #[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum GfxVendors { pub enum GfxVendors {
Nvidia, Nvidia,
Integrated, Integrated,
Compute, Compute,
Vfio,
Hybrid, Hybrid,
} }
@@ -18,10 +20,12 @@ impl FromStr for GfxVendors {
"nvidia" => Ok(GfxVendors::Nvidia), "nvidia" => Ok(GfxVendors::Nvidia),
"hybrid" => Ok(GfxVendors::Hybrid), "hybrid" => Ok(GfxVendors::Hybrid),
"compute" => Ok(GfxVendors::Compute), "compute" => Ok(GfxVendors::Compute),
"vfio" => Ok(GfxVendors::Vfio),
"integrated" => Ok(GfxVendors::Integrated), "integrated" => Ok(GfxVendors::Integrated),
"nvidia\n" => Ok(GfxVendors::Nvidia), "nvidia\n" => Ok(GfxVendors::Nvidia),
"hybrid\n" => Ok(GfxVendors::Hybrid), "hybrid\n" => Ok(GfxVendors::Hybrid),
"compute\n" => Ok(GfxVendors::Compute), "compute\n" => Ok(GfxVendors::Compute),
"vfio\n" => Ok(GfxVendors::Vfio),
"integrated\n" => Ok(GfxVendors::Integrated), "integrated\n" => Ok(GfxVendors::Integrated),
_ => Err(GraphicsError::ParseVendor), _ => Err(GraphicsError::ParseVendor),
} }
@@ -34,6 +38,7 @@ impl From<&GfxVendors> for &str {
GfxVendors::Nvidia => "nvidia", GfxVendors::Nvidia => "nvidia",
GfxVendors::Hybrid => "hybrid", GfxVendors::Hybrid => "hybrid",
GfxVendors::Compute => "compute", GfxVendors::Compute => "compute",
GfxVendors::Vfio => "vfio",
GfxVendors::Integrated => "integrated", GfxVendors::Integrated => "integrated",
} }
} }
@@ -45,38 +50,19 @@ impl From<GfxVendors> for &str {
} }
} }
#[derive(Debug)] #[derive(Debug, Type, PartialEq, Copy, Clone, Deserialize, Serialize)]
pub enum GfxCtrlAction { pub enum GfxRequiredUserAction {
Logout,
Reboot, Reboot,
RestartX,
None, None,
} }
impl FromStr for GfxCtrlAction { impl From<&GfxRequiredUserAction> for &str {
type Err = GraphicsError; fn from(gfx: &GfxRequiredUserAction) -> &'static str {
match gfx {
fn from_str(s: &str) -> Result<Self, GraphicsError> { GfxRequiredUserAction::Logout => "logout",
match s.to_lowercase().as_str() { GfxRequiredUserAction::Reboot => "reboot",
"reboot" => Ok(GfxCtrlAction::Reboot), GfxRequiredUserAction::None => "no action",
"restartx" => Ok(GfxCtrlAction::RestartX),
"none" => Ok(GfxCtrlAction::None),
_ => Err(GraphicsError::ParseVendor),
} }
} }
} }
impl From<&GfxCtrlAction> for &str {
fn from(mode: &GfxCtrlAction) -> Self {
match mode {
GfxCtrlAction::Reboot => "reboot",
GfxCtrlAction::RestartX => "restartx",
GfxCtrlAction::None => "none",
}
}
}
impl From<GfxCtrlAction> for &str {
fn from(mode: GfxCtrlAction) -> Self {
(&mode).into()
}
}