mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Trial of blocking vfio/compute unless in integrated mode
This commit is contained in:
@@ -10,13 +10,10 @@ use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2, ANIME_DATA_LEN};
|
|||||||
use rog_aura::{self, AuraEffect};
|
use rog_aura::{self, AuraEffect};
|
||||||
use rog_dbus::RogDbusClient;
|
use rog_dbus::RogDbusClient;
|
||||||
use rog_profiles::profiles::Profile;
|
use rog_profiles::profiles::Profile;
|
||||||
use rog_types::{
|
use rog_types::{gfx_vendors::{GfxRequiredUserAction, GfxVendors}, supported::{
|
||||||
gfx_vendors::GfxVendors,
|
|
||||||
supported::{
|
|
||||||
FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
|
FanCpuSupportedFunctions, LedSupportedFunctions, RogBiosSupportedFunctions,
|
||||||
SupportedFunctions,
|
SupportedFunctions,
|
||||||
},
|
}};
|
||||||
};
|
|
||||||
use std::{env::args, path::Path};
|
use std::{env::args, path::Path};
|
||||||
use yansi_term::Colour::Green;
|
use yansi_term::Colour::Green;
|
||||||
use yansi_term::Colour::Red;
|
use yansi_term::Colour::Red;
|
||||||
@@ -309,11 +306,27 @@ fn do_gfx(
|
|||||||
err
|
err
|
||||||
})?;
|
})?;
|
||||||
let res = dbus.gfx_wait_changed()?;
|
let res = dbus.gfx_wait_changed()?;
|
||||||
println!(
|
match res {
|
||||||
"Graphics mode changed to {}. User action required is: {}",
|
GfxRequiredUserAction::Integrated => {
|
||||||
<&str>::from(mode),
|
println!(
|
||||||
<&str>::from(&res)
|
"You must change to Integrated before you can change to {}",
|
||||||
);
|
<&str>::from(mode)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
GfxRequiredUserAction::Logout | GfxRequiredUserAction::Reboot => {
|
||||||
|
println!(
|
||||||
|
"Graphics mode changed to {}. User action required is: {}",
|
||||||
|
<&str>::from(mode),
|
||||||
|
<&str>::from(&res)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
GfxRequiredUserAction::None => {
|
||||||
|
println!(
|
||||||
|
"Graphics mode changed to {}",
|
||||||
|
<&str>::from(mode)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
std::process::exit(0)
|
std::process::exit(0)
|
||||||
}
|
}
|
||||||
if command.get {
|
if command.get {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ use logind_zbus::{
|
|||||||
ManagerProxy, SessionProxy,
|
ManagerProxy, SessionProxy,
|
||||||
};
|
};
|
||||||
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
|
use rog_types::gfx_vendors::{GfxPower, GfxRequiredUserAction, GfxVendors};
|
||||||
|
use std::iter::FromIterator;
|
||||||
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::{process::Command, thread::sleep, time::Duration};
|
use std::{process::Command, thread::sleep, time::Duration};
|
||||||
use std::{str::FromStr, sync::mpsc};
|
use std::{str::FromStr, sync::mpsc};
|
||||||
use std::{sync::Arc, sync::Mutex};
|
use std::{sync::Arc, sync::Mutex};
|
||||||
@@ -126,7 +126,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Associated method to get which vendor mode is set
|
/// Associated method to get which vendor mode is set
|
||||||
pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
|
pub(super) fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
|
||||||
if let Ok(config) = self.config.lock() {
|
if let Ok(config) = self.config.lock() {
|
||||||
if let Some(mode) = config.gfx_tmp_mode {
|
if let Some(mode) = config.gfx_tmp_mode {
|
||||||
return Ok(mode);
|
return Ok(mode);
|
||||||
@@ -275,6 +275,7 @@ impl CtrlGraphics {
|
|||||||
.map_err(|err| RogError::Command("device unbind error".into(), err))
|
.map_err(|err| RogError::Command("device unbind error".into(), err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add or remove driver modules
|
||||||
fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> {
|
fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> {
|
||||||
let mut cmd = Command::new(action);
|
let mut cmd = Command::new(action);
|
||||||
cmd.arg(driver);
|
cmd.arg(driver);
|
||||||
@@ -359,14 +360,15 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
while count <= 5 {
|
while count <= (4 * 3) {
|
||||||
|
// 3 seconds max
|
||||||
let output = cmd
|
let output = cmd
|
||||||
.output()
|
.output()
|
||||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||||
if output.stdout.starts_with(state.as_bytes()) {
|
if output.stdout.starts_with(state.as_bytes()) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
Err(GfxError::DisplayManagerTimeout(state.into()).into())
|
Err(GfxError::DisplayManagerTimeout(state.into()).into())
|
||||||
@@ -374,9 +376,10 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
/// Determine if we need to logout/thread. Integrated<->Vfio mode does not
|
/// Determine if we need to logout/thread. Integrated<->Vfio mode does not
|
||||||
/// require logout.
|
/// require logout.
|
||||||
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
|
fn is_logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
|
||||||
if let Ok(config) = self.config.lock() {
|
if let Ok(config) = self.config.lock() {
|
||||||
let current = config.gfx_mode;
|
let current = config.gfx_mode;
|
||||||
|
// Modes that can switch without logout
|
||||||
if matches!(
|
if matches!(
|
||||||
current,
|
current,
|
||||||
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
|
GfxVendors::Integrated | GfxVendors::Vfio | GfxVendors::Compute
|
||||||
@@ -386,22 +389,28 @@ impl CtrlGraphics {
|
|||||||
) {
|
) {
|
||||||
return GfxRequiredUserAction::None;
|
return GfxRequiredUserAction::None;
|
||||||
}
|
}
|
||||||
|
// Modes that require a switch to integrated first
|
||||||
|
if matches!(current, GfxVendors::Nvidia | GfxVendors::Hybrid)
|
||||||
|
&& matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio)
|
||||||
|
{
|
||||||
|
return GfxRequiredUserAction::Integrated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GfxRequiredUserAction::Logout
|
GfxRequiredUserAction::Logout
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the config changes and add/remove drivers and devices depending
|
/// Do a full setup flow for the chosen mode:
|
||||||
/// on selected mode:
|
|
||||||
///
|
///
|
||||||
/// Tasks:
|
/// Tasks:
|
||||||
|
/// - rescan for devices
|
||||||
/// - write xorg config
|
/// - write xorg config
|
||||||
/// - write modprobe config
|
/// - write modprobe config
|
||||||
/// - 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
|
/// The daemon needs direct access to this function when it detects that the
|
||||||
pub fn do_vendor_tasks(
|
/// bios has G-Sync switch is enabled
|
||||||
|
pub fn do_mode_setup_tasks(
|
||||||
vendor: GfxVendors,
|
vendor: GfxVendors,
|
||||||
vfio_enable: bool,
|
vfio_enable: bool,
|
||||||
devices: &[GraphicsDevice],
|
devices: &[GraphicsDevice],
|
||||||
@@ -425,8 +434,14 @@ impl CtrlGraphics {
|
|||||||
dev.set_runtime_pm(sysfs_class::RuntimePowerManagement::On)?;
|
dev.set_runtime_pm(sysfs_class::RuntimePowerManagement::On)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
// Only these modes should have xorg config
|
||||||
Self::write_xorg_conf(vendor)?;
|
if matches!(
|
||||||
|
vendor,
|
||||||
|
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Integrated
|
||||||
|
) {
|
||||||
|
Self::write_xorg_conf(vendor)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Write different modprobe to enable boot control to work
|
// Write different modprobe to enable boot control to work
|
||||||
Self::write_modprobe_conf(vendor, devices)?;
|
Self::write_modprobe_conf(vendor, devices)?;
|
||||||
|
|
||||||
@@ -492,7 +507,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Spools until all user sessions are ended then switches to requested mode
|
/// Spools until all user sessions are ended then switches to requested mode
|
||||||
fn fire_starter(
|
fn create_mode_change_thread(
|
||||||
vendor: GfxVendors,
|
vendor: GfxVendors,
|
||||||
devices: Vec<GraphicsDevice>,
|
devices: Vec<GraphicsDevice>,
|
||||||
bus: PciBus,
|
bus: PciBus,
|
||||||
@@ -538,7 +553,7 @@ impl CtrlGraphics {
|
|||||||
Self::do_display_manager_action("stop")?;
|
Self::do_display_manager_action("stop")?;
|
||||||
Self::wait_display_manager_state("inactive")?;
|
Self::wait_display_manager_state("inactive")?;
|
||||||
|
|
||||||
let mut mode_to_save = vendor;
|
let mut mode_to_save = vendor;
|
||||||
// Need to change to integrated before we can change to vfio or compute
|
// Need to change to integrated before we can change to vfio or compute
|
||||||
if let Ok(mut config) = config.try_lock() {
|
if let Ok(mut config) = config.try_lock() {
|
||||||
// Since we have a lock, reset tmp to none. This thread should only ever run
|
// Since we have a lock, reset tmp to none. This thread should only ever run
|
||||||
@@ -547,17 +562,16 @@ impl CtrlGraphics {
|
|||||||
//
|
//
|
||||||
let vfio_enable = config.gfx_vfio_enable;
|
let vfio_enable = config.gfx_vfio_enable;
|
||||||
|
|
||||||
|
// Failsafe. In the event this loop is run with a switch from nvidia in use
|
||||||
|
// to vfio or compute do a forced switch to integrated instead to prevent issues
|
||||||
if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio)
|
if matches!(vendor, GfxVendors::Compute | GfxVendors::Vfio)
|
||||||
&& matches!(config.gfx_mode, GfxVendors::Nvidia | GfxVendors::Hybrid)
|
&& matches!(config.gfx_mode, GfxVendors::Nvidia | GfxVendors::Hybrid)
|
||||||
{
|
{
|
||||||
Self::do_vendor_tasks(GfxVendors::Integrated, vfio_enable, &devices, &bus)?;
|
Self::do_mode_setup_tasks(GfxVendors::Integrated, vfio_enable, &devices, &bus)?;
|
||||||
Self::do_display_manager_action("restart")?;
|
Self::do_display_manager_action("restart")?;
|
||||||
sleep(Duration::from_millis(1500)); // Allow some time for the desktop to start
|
|
||||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
|
||||||
config.gfx_tmp_mode = Some(vendor);
|
|
||||||
mode_to_save = GfxVendors::Integrated;
|
mode_to_save = GfxVendors::Integrated;
|
||||||
} else {
|
} else {
|
||||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
Self::do_display_manager_action("restart")?;
|
Self::do_display_manager_action("restart")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -572,7 +586,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Before starting a new thread the old one *must* be cancelled
|
/// Before starting a new thread the old one *must* be cancelled
|
||||||
fn cancel_thread(&self) {
|
fn cancel_mode_change_thread(&self) {
|
||||||
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
|
||||||
@@ -587,7 +601,7 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The thread is used only in cases where a logout is required
|
/// The thread is used only in cases where a logout is required
|
||||||
fn setup_thread(&mut self, vendor: GfxVendors) {
|
fn setup_mode_change_thread(&mut self, vendor: GfxVendors) {
|
||||||
let config = self.config.clone();
|
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();
|
||||||
@@ -595,16 +609,16 @@ impl CtrlGraphics {
|
|||||||
if let Ok(mut lock) = self.thread_kill.lock() {
|
if let Ok(mut lock) = self.thread_kill.lock() {
|
||||||
*lock = Some(tx);
|
*lock = Some(tx);
|
||||||
}
|
}
|
||||||
let killer = self.thread_kill.clone();
|
let thread_kill = self.thread_kill.clone();
|
||||||
|
|
||||||
let _join: JoinHandle<()> = std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
Self::fire_starter(vendor, devices, bus, rx, config)
|
Self::create_mode_change_thread(vendor, devices, bus, rx, config)
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
error!("GFX: {}", err);
|
error!("GFX: {}", err);
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
// clear the tx/rx when done
|
// clear the tx/rx when done
|
||||||
if let Ok(mut lock) = killer.try_lock() {
|
if let Ok(mut lock) = thread_kill.try_lock() {
|
||||||
*lock = None;
|
*lock = None;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -615,10 +629,7 @@ impl CtrlGraphics {
|
|||||||
/// to switch modes.
|
/// to switch modes.
|
||||||
///
|
///
|
||||||
/// For manually calling (not on boot/startup) via dbus
|
/// For manually calling (not on boot/startup) via dbus
|
||||||
pub fn set_gfx_config(
|
pub fn set_gfx_mode(&mut self, vendor: GfxVendors) -> Result<GfxRequiredUserAction, RogError> {
|
||||||
&mut self,
|
|
||||||
vendor: GfxVendors,
|
|
||||||
) -> Result<GfxRequiredUserAction, RogError> {
|
|
||||||
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
|
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
|
||||||
if gsync == 1 {
|
if gsync == 1 {
|
||||||
return Err(GfxError::GsyncModeActive.into());
|
return Err(GfxError::GsyncModeActive.into());
|
||||||
@@ -636,29 +647,40 @@ impl CtrlGraphics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must always cancel any thread running
|
// Must always cancel any thread running
|
||||||
self.cancel_thread();
|
self.cancel_mode_change_thread();
|
||||||
// determine which method we need here
|
// determine which method we need here
|
||||||
let action_required = self.logout_required(vendor);
|
let action_required = self.is_logout_required(vendor);
|
||||||
if matches!(action_required, GfxRequiredUserAction::Logout) {
|
|
||||||
// Yeah need the thread to check if all users are logged out
|
match action_required {
|
||||||
info!("GFX: mode change requires a logout to complete");
|
GfxRequiredUserAction::Logout => {
|
||||||
self.setup_thread(vendor);
|
info!("GFX: mode change requires a logout to complete");
|
||||||
} else {
|
self.setup_mode_change_thread(vendor);
|
||||||
// Okay cool, we can switch on/off vfio
|
}
|
||||||
info!("GFX: mode change does not require logout");
|
GfxRequiredUserAction::Reboot => {
|
||||||
let devices = self.nvidia.clone();
|
info!("GFX: mode change requires reboot");
|
||||||
let bus = self.bus.clone();
|
let devices = self.nvidia.clone();
|
||||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
let bus = self.bus.clone();
|
||||||
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
if let Ok(mut config) = self.config.try_lock() {
|
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
||||||
if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) {
|
},
|
||||||
config.gfx_tmp_mode = Some(vendor);
|
GfxRequiredUserAction::Integrated => {
|
||||||
} else {
|
info!("GFX: mode change requires user to be in Integrated mode first");
|
||||||
|
}
|
||||||
|
GfxRequiredUserAction::None => {
|
||||||
|
info!("GFX: mode change does not require logout");
|
||||||
|
let devices = self.nvidia.clone();
|
||||||
|
let bus = self.bus.clone();
|
||||||
|
Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
|
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
|
||||||
|
if let Ok(mut config) = self.config.try_lock() {
|
||||||
config.gfx_tmp_mode = None;
|
config.gfx_tmp_mode = None;
|
||||||
|
if matches!(vendor, GfxVendors::Vfio | GfxVendors::Compute) {
|
||||||
|
config.gfx_tmp_mode = Some(vendor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: undo if failed? Save last mode, catch errors...
|
|
||||||
Ok(action_required)
|
Ok(action_required)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,7 +696,7 @@ impl CtrlGraphics {
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::do_vendor_tasks(vendor, vfio_enable, &devices, &bus)?;
|
Self::do_mode_setup_tasks(vendor, vfio_enable, &devices, &bus)?;
|
||||||
Self::toggle_fallback_service(vendor)?;
|
Self::toggle_fallback_service(vendor)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ impl CtrlGraphics {
|
|||||||
|
|
||||||
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
|
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
|
||||||
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
|
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
|
||||||
let msg = self.set_gfx_config(vendor).map_err(|err| {
|
let msg = self.set_gfx_mode(vendor).map_err(|err| {
|
||||||
error!("GFX: {}", err);
|
error!("GFX: {}", err);
|
||||||
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
|
||||||
})?;
|
})?;
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
|
||||||
let devices = ctrl.devices();
|
let devices = ctrl.devices();
|
||||||
let bus = ctrl.bus();
|
let bus = ctrl.bus();
|
||||||
CtrlGraphics::do_vendor_tasks(
|
CtrlGraphics::do_mode_setup_tasks(
|
||||||
GfxVendors::Nvidia,
|
GfxVendors::Nvidia,
|
||||||
false,
|
false,
|
||||||
&devices,
|
&devices,
|
||||||
@@ -165,7 +165,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
|
|||||||
info!("Dedicated GFX toggle is off");
|
info!("Dedicated GFX toggle is off");
|
||||||
let devices = ctrl.devices();
|
let devices = ctrl.devices();
|
||||||
let bus = ctrl.bus();
|
let bus = ctrl.bus();
|
||||||
CtrlGraphics::do_vendor_tasks(
|
CtrlGraphics::do_mode_setup_tasks(
|
||||||
config.gfx_mode,
|
config.gfx_mode,
|
||||||
false,
|
false,
|
||||||
&devices,
|
&devices,
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ impl From<GfxVendors> for &str {
|
|||||||
pub enum GfxRequiredUserAction {
|
pub enum GfxRequiredUserAction {
|
||||||
Logout,
|
Logout,
|
||||||
Reboot,
|
Reboot,
|
||||||
|
Integrated,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +95,7 @@ impl From<&GfxRequiredUserAction> for &str {
|
|||||||
match gfx {
|
match gfx {
|
||||||
GfxRequiredUserAction::Logout => "logout",
|
GfxRequiredUserAction::Logout => "logout",
|
||||||
GfxRequiredUserAction::Reboot => "reboot",
|
GfxRequiredUserAction::Reboot => "reboot",
|
||||||
|
GfxRequiredUserAction::Integrated => "switch to integrated first",
|
||||||
GfxRequiredUserAction::None => "no action",
|
GfxRequiredUserAction::None => "no action",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user