Create (stubbed) Asus ROG Ally driver

This commit is contained in:
NGnius (Graham) 2024-09-06 15:57:46 -04:00
parent cc26a2a91f
commit f5303d077a
23 changed files with 550 additions and 23 deletions

61
backend/Cargo.lock generated
View file

@ -201,7 +201,7 @@ version = "0.66.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
dependencies = [
"bitflags",
"bitflags 2.4.1",
"cexpr",
"clang-sys",
"lazy_static",
@ -218,6 +218,18 @@ dependencies = [
"which",
]
[[package]]
name = "bit_field"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
@ -1162,6 +1174,13 @@ dependencies = [
"universal-hash",
]
[[package]]
name = "powerbox"
version = "0.1.0"
dependencies = [
"sysfuss 0.4.0",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
@ -1180,13 +1199,14 @@ dependencies = [
"libryzenadj",
"limits_core",
"log",
"procbox",
"regex",
"ron",
"serde",
"serde_json",
"simplelog",
"smokepatio",
"sysfuss",
"sysfuss 0.3.0",
"tokio",
"ureq",
"usdpl-back",
@ -1227,6 +1247,15 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "procbox"
version = "0.1.0"
dependencies = [
"powerbox",
"sysfuss 0.4.0",
"x86",
]
[[package]]
name = "quote"
version = "1.0.33"
@ -1266,6 +1295,15 @@ dependencies = [
"getrandom",
]
[[package]]
name = "raw-cpuid"
version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.10.2"
@ -1316,7 +1354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64 0.21.5",
"bitflags",
"bitflags 2.4.1",
"serde",
"serde_derive",
]
@ -1339,7 +1377,7 @@ version = "0.38.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316"
dependencies = [
"bitflags",
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
@ -1542,6 +1580,10 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f33bae529511a671b5f2ed4cc46ae0b2ccdf8c03ccf7eebe95a5a886ff7914dc"
[[package]]
name = "sysfuss"
version = "0.4.0"
[[package]]
name = "termcolor"
version = "1.1.3"
@ -2166,6 +2208,17 @@ dependencies = [
"memchr",
]
[[package]]
name = "x86"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
dependencies = [
"bit_field",
"bitflags 1.3.2",
"raw-cpuid",
]
[[package]]
name = "zeroize"
version = "1.3.0"

View file

@ -17,6 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
ron = "0.8"
sysfuss = { version = "0.3", features = ["derive"] }#,path = "../../sysfs-nav"}
procbox = { version = "0.1", path = "../../powerbox/crates/procbox" }
# async
tokio = { version = "*", features = ["time"] }

View file

@ -9,6 +9,7 @@ pub enum CpuLimitType {
SteamDeck,
#[serde(rename = "GabeBoySP", alias = "SteamDeckOLED")]
SteamDeckOLED,
ROGAlly,
Generic,
GenericAMD,
Unknown,

View file

@ -8,6 +8,7 @@ pub enum GpuLimitType {
SteamDeck,
#[serde(rename = "GabeBoySP", alias = "SteamDeckOLED")]
SteamDeckOLED,
ROGAlly,
Generic,
GenericAMD,
Unknown,

View file

@ -12,6 +12,8 @@ pub enum DriverJson {
Generic,
#[serde(rename = "generic-amd")]
GenericAMD,
#[serde(rename = "rog-ally")]
ROGAlly,
#[serde(rename = "unknown")]
Unknown,
#[default]

View file

@ -138,6 +138,13 @@ pub fn auto_detect0(
)
.variant(super::super::steam_deck::Model::OLED),
),
CpuLimitType::ROGAlly => Box::new(
crate::settings::rog_ally::Cpus::from_json_and_limits(
settings.cpus.clone(),
settings.version,
relevant_limits.cpu.limits,
)
),
CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::<
crate::settings::generic::Cpu,
>::from_json_and_limits(
@ -185,6 +192,13 @@ pub fn auto_detect0(
)
.variant(super::super::steam_deck::Model::OLED),
),
GpuLimitType::ROGAlly => Box::new(
crate::settings::rog_ally::Gpu::from_json_and_limits(
settings.gpu.clone(),
settings.version,
relevant_limits.gpu.limits,
)
),
GpuLimitType::Generic => {
Box::new(crate::settings::generic::Gpu::from_json_and_limits(
settings.gpu.clone(),
@ -270,6 +284,9 @@ pub fn auto_detect0(
crate::settings::steam_deck::Cpus::from_limits(relevant_limits.cpu.limits)
.variant(super::super::steam_deck::Model::OLED),
),
CpuLimitType::ROGAlly => Box::new(
crate::settings::rog_ally::Cpus::from_limits(relevant_limits.cpu.limits)
),
CpuLimitType::Generic => Box::new(crate::settings::generic::Cpus::<
crate::settings::generic::Cpu,
>::from_limits(
@ -294,6 +311,9 @@ pub fn auto_detect0(
crate::settings::steam_deck::Gpu::from_limits(relevant_limits.gpu.limits)
.variant(super::super::steam_deck::Model::OLED),
),
GpuLimitType::ROGAlly => Box::new(
crate::settings::rog_ally::Gpu::from_limits(relevant_limits.gpu.limits)
),
GpuLimitType::Generic => Box::new(crate::settings::generic::Gpu::from_limits(
relevant_limits.gpu.limits,
)),

View file

@ -272,11 +272,11 @@ impl TCpu for Cpu {
});
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
log::debug!(
"dev_mode_Cpu::get_clock_limits(self) -> {:?}",
self.clock_limits.as_ref()
);
self.clock_limits.as_ref()
self.clock_limits.clone()
}
}

View file

@ -188,12 +188,12 @@ impl TGpu for Gpu {
});
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
log::debug!(
"dev_mode_Gpu::get_clock_limits(self) -> {:?}",
self.clock_limits.as_ref()
);
self.clock_limits.as_ref()
self.clock_limits.clone()
}
fn memory_clock(&mut self, speed: Option<u64>) {

View file

@ -37,7 +37,8 @@ pub fn maybe_do_button() {
match super::auto_detect_provider() {
DriverJson::SteamDeck | DriverJson::SteamDeckOLED => {
crate::settings::steam_deck::flash_led();
}
},
DriverJson::ROGAlly => log::info!("Roggle boggle smoggle flollop"),
DriverJson::Generic | DriverJson::GenericAMD => {
log::warn!("You need to come up with something fun on generic")
}

View file

@ -441,8 +441,8 @@ impl TCpu for Cpu {
}
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.clock_limits.as_ref()
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.clock_limits.clone()
}
}

View file

@ -303,8 +303,8 @@ impl TGpu for Gpu {
}
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.clock_limits.as_ref()
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.clock_limits.clone()
}
fn memory_clock(&mut self, _speed: Option<u64>) {}

View file

@ -149,7 +149,7 @@ impl TCpu for Cpu {
// TODO: support this
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.generic.get_clock_limits()
}
}

View file

@ -368,7 +368,7 @@ impl TGpu for Gpu {
self.generic.clock_limits(limits)
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.generic.get_clock_limits()
}

View file

@ -11,6 +11,7 @@ pub mod generic;
pub mod generic_amd;
pub mod steam_deck;
pub mod unknown;
pub mod rog_ally;
pub use detect::{
auto_detect0, auto_detect_provider, get_dev_messages,

View file

@ -0,0 +1,155 @@
use crate::persist::CpuJson;
use crate::settings::generic::{Cpu as GenericCpu, Cpus as GenericCpus, FromGenericCpuInfo};
use crate::settings::MinMax;
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TCpu, TCpus};
#[derive(Debug)]
pub struct Cpus {
generic: GenericCpus<Cpu>,
}
impl ProviderBuilder<Vec<CpuJson>, limits_core::json_v2::GenericCpusLimit> for Cpus {
fn from_limits(limits: limits_core::json_v2::GenericCpusLimit) -> Self {
Self {
generic: GenericCpus::from_limits(limits),
}
}
fn from_json_and_limits(
other: Vec<CpuJson>,
version: u64,
limits: limits_core::json_v2::GenericCpusLimit,
) -> Self {
Self {
generic: GenericCpus::from_json_and_limits(other, version, limits),
}
}
}
impl OnResume for Cpus {
fn on_resume(&self) -> Result<(), Vec<SettingError>> {
self.generic.on_resume()
// TODO
}
}
impl OnSet for Cpus {
fn on_set(&mut self) -> Result<(), Vec<SettingError>> {
self.generic.on_set()
// TODO
}
}
impl crate::settings::OnPowerEvent for Cpus {}
impl crate::settings::OnLoad for Cpus {
fn on_load(&mut self) -> Result<(), Vec<SettingError>> {
Ok(())
}
}
impl crate::settings::OnUnload for Cpus {
fn on_unload(&mut self) -> Result<(), Vec<SettingError>> {
Ok(())
}
}
impl TCpus for Cpus {
fn limits(&self) -> crate::api::CpusLimits {
self.generic.limits()
}
fn json(&self) -> Vec<crate::persist::CpuJson> {
self.generic.json() // TODO
}
fn cpus(&mut self) -> Vec<&mut dyn TCpu> {
self.generic.cpus() // TODO
}
fn len(&self) -> usize {
self.generic.len() // TODO
}
fn smt(&mut self) -> &'_ mut bool {
self.generic.smt()
}
fn provider(&self) -> crate::persist::DriverJson {
crate::persist::DriverJson::GenericAMD
}
}
#[derive(Debug)]
pub struct Cpu {
generic: GenericCpu,
}
impl FromGenericCpuInfo for Cpu {
fn from_limits(cpu_index: usize, limits: limits_core::json_v2::GenericCpuLimit) -> Self {
let gen = GenericCpu::from_limits(cpu_index, limits.clone());
Self { generic: gen }
}
fn from_json_and_limits(
other: CpuJson,
version: u64,
cpu_index: usize,
limits: limits_core::json_v2::GenericCpuLimit,
) -> Self {
let gen = GenericCpu::from_json_and_limits(other, version, cpu_index, limits);
Self { generic: gen }
}
}
impl AsRef<GenericCpu> for Cpu {
fn as_ref(&self) -> &GenericCpu {
&self.generic
}
}
impl AsMut<GenericCpu> for Cpu {
fn as_mut(&mut self) -> &mut GenericCpu {
&mut self.generic
}
}
impl OnResume for Cpu {
fn on_resume(&self) -> Result<(), Vec<SettingError>> {
self.generic.on_resume()
// TODO
}
}
impl OnSet for Cpu {
fn on_set(&mut self) -> Result<(), Vec<SettingError>> {
self.generic.on_set()
// TODO
}
}
impl crate::settings::OnPowerEvent for Cpu {}
impl TCpu for Cpu {
fn online(&mut self) -> &mut bool {
self.generic.online()
}
fn governor(&mut self, governor: String) {
self.generic.governor(governor)
}
fn get_governor(&self) -> &'_ str {
self.generic.get_governor()
}
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {
//self.generic.clock_limits(limits)
// TODO: support this
}
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.generic.get_clock_limits()
}
}

View file

@ -0,0 +1,286 @@
use limits_core::json_v2::GenericGpuLimit;
use sysfuss::{capability::attributes, BasicEntityPath, SysEntity};
use procbox::combo::AmdGpu;
use crate::api::RangeLimit;
use crate::persist::{GpuJson, MinMaxJson};
use crate::settings::{min_max_from_json, MinMax};
use crate::settings::{OnResume, OnSet, SettingError};
use crate::settings::{ProviderBuilder, TGpu};
//#[derive(Clone)]
pub struct Gpu {
gpu_impl: AmdGpu,
settings: GpuJson,
limits: GenericGpuLimit,
}
impl Gpu {
fn find_amdgpu(root: Option<impl AsRef<std::path::Path>>) -> AmdGpu {
let root = crate::settings::util::root_or_default_sysfs(root);
let ent_path = match root.class(
"drm",
attributes(
crate::settings::util::CARD_NEEDS
.into_iter()
.map(|s| s.to_string()),
),
) {
Ok(iter) => {
let card = iter
.filter(|ent| if let Ok(name) = ent.name() { name.starts_with("card")} else { false })
//.filter(|ent| super::util::card_also_has(ent, CARD_EXTENSIONS))
.next()
.unwrap_or_else(|| {
log::error!("Failed to find ROG Ally gpu drm in sysfs (no results), using naive fallback");
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card1"))
});
log::info!(
"Found ROG Ally gpu drm in sysfs: {}",
card.as_ref().display()
);
card
}
Err(e) => {
log::error!(
"Failed to find ROG Ally gpu drm in sysfs ({}), using naive fallback",
e
);
BasicEntityPath::new(root.as_ref().join("sys/class/drm/card1"))
}
};
AmdGpu::new(ent_path)
}
}
impl core::fmt::Debug for Gpu {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("rog_ally::Gpu")
.field("limits", &self.limits)
//.field("gpu_impl", &self.gpu_impl)
.finish_non_exhaustive()
}
}
impl ProviderBuilder<GpuJson, GenericGpuLimit> for Gpu {
fn from_json_and_limits(persistent: GpuJson, _version: u64, limits: GenericGpuLimit) -> Self {
Self {
gpu_impl: Self::find_amdgpu(persistent.root.clone()),
settings: persistent,
limits,
}
}
fn from_limits(limits: GenericGpuLimit) -> Self {
Self {
gpu_impl: Self::find_amdgpu(None::<&'static str>),
settings: GpuJson::default(),
limits,
}
}
}
impl Into<GpuJson> for Gpu {
#[inline]
fn into(self) -> GpuJson {
self.settings
}
}
impl OnSet for Gpu {
fn on_set(&mut self) -> Result<(), Vec<SettingError>> {
// TODO
Ok(())
}
}
impl OnResume for Gpu {
fn on_resume(&self) -> Result<(), Vec<SettingError>> {
// TODO
Ok(())
}
}
impl crate::settings::OnPowerEvent for Gpu {}
impl crate::settings::OnLoad for Gpu {
fn on_load(&mut self) -> Result<(), Vec<SettingError>> {
Ok(())
}
}
impl crate::settings::OnUnload for Gpu {
fn on_unload(&mut self) -> Result<(), Vec<SettingError>> {
Ok(())
}
}
impl TGpu for Gpu {
fn limits(&self) -> crate::api::GpuLimits {
crate::api::GpuLimits {
fast_ppt_limits: self
.limits
.fast_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {
x
}
}),
fast_ppt_default: {
let def = self
.limits
.fast_ppt_default
.or_else(|| self.limits.fast_ppt.and_then(|x| x.max))
.unwrap_or(15);
if let Some(ppt_divisor) = self.limits.ppt_divisor {
def / ppt_divisor
} else {
def
}
},
slow_ppt_limits: self
.limits
.slow_ppt
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15)))
.map(|mut x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x.min /= ppt_divisor;
x.max /= ppt_divisor;
x
} else {
x
}
}),
slow_ppt_default: {
let def = self
.limits
.slow_ppt_default
.or_else(|| self.limits.slow_ppt.and_then(|x| x.max))
.unwrap_or(15);
if let Some(ppt_divisor) = self.limits.ppt_divisor {
def / ppt_divisor
} else {
def
}
},
ppt_step: self.limits.ppt_step.unwrap_or(1),
tdp_limits: self
.limits
.tdp
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
tdp_boost_limits: self
.limits
.tdp_boost
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(15_000_000))),
tdp_step: self.limits.tdp_step.unwrap_or(42),
clock_min_limits: self
.limits
.clock_min
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))),
clock_max_limits: self
.limits
.clock_max
.clone()
.map(|x| RangeLimit::new(x.min.unwrap_or(0), x.max.unwrap_or(3_000))),
clock_step: self.limits.clock_step.unwrap_or(100),
memory_control: None,
memory_step: 100,
}
}
fn json(&self) -> crate::persist::GpuJson {
self.settings.clone()
}
fn ppt(&mut self, fast: Option<u64>, slow: Option<u64>) {
if let Some(fast_lims) = &self.limits.fast_ppt {
self.settings.fast_ppt = fast
.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x * ppt_divisor
} else {
x
}
})
.map(|x| {
x.clamp(
fast_lims.min.unwrap_or(0),
fast_lims.max.unwrap_or(u64::MAX),
)
});
}
if let Some(slow_lims) = &self.limits.slow_ppt {
self.settings.slow_ppt = slow
.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x * ppt_divisor
} else {
x
}
})
.map(|x| {
x.clamp(
slow_lims.min.unwrap_or(0),
slow_lims.max.unwrap_or(u64::MAX),
)
});
}
}
fn get_ppt(&self) -> (Option<u64>, Option<u64>) {
(
self.settings.fast_ppt.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x / ppt_divisor
} else {
x
}
}),
self.settings.slow_ppt.map(|x| {
if let Some(ppt_divisor) = self.limits.ppt_divisor {
x / ppt_divisor
} else {
x
}
}),
)
}
fn clock_limits(&mut self, limits: Option<MinMax<u64>>) {
if let Some(clock_min) = &self.limits.clock_min {
if let Some(clock_max) = &self.limits.clock_max {
self.settings.clock_limits = limits.map(|x| {
MinMaxJson {
min: x.min.clamp(clock_min.min, clock_min.max),
max: x.max.clamp(clock_max.max, clock_max.max)
}
});
}
}
}
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.settings.clock_limits.clone().map(|mmj| min_max_from_json(mmj, 1))
}
fn memory_clock(&mut self, _speed: Option<u64>) {}
fn get_memory_clock(&self) -> Option<u64> {
None
}
fn provider(&self) -> crate::persist::DriverJson {
crate::persist::DriverJson::Generic
}
}

View file

@ -0,0 +1,6 @@
mod cpu;
mod gpu;
mod util;
pub use cpu::Cpus;
pub use gpu::Gpu;

View file

View file

@ -723,8 +723,8 @@ impl TCpu for Cpu {
self.clock_limits = limits;
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.clock_limits.as_ref()
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.clock_limits.clone()
}
}

View file

@ -717,8 +717,8 @@ impl TGpu for Gpu {
self.clock_limits = limits;
}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
self.clock_limits.as_ref()
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
self.clock_limits.clone()
}
fn memory_clock(&mut self, speed: Option<u64>) {

View file

@ -65,7 +65,7 @@ pub trait TGpu: OnSet + OnResume + OnPowerEvent + OnLoad + OnUnload + Debug + Se
fn clock_limits(&mut self, limits: Option<MinMax<u64>>);
fn get_clock_limits(&self) -> Option<&MinMax<u64>>;
fn get_clock_limits(&self) -> Option<MinMax<u64>>;
fn memory_clock(&mut self, speed: Option<u64>);
@ -101,7 +101,7 @@ pub trait TCpu: Debug + Send {
fn clock_limits(&mut self, limits: Option<MinMax<u64>>);
fn get_clock_limits(&self) -> Option<&MinMax<u64>>;
fn get_clock_limits(&self) -> Option<MinMax<u64>>;
}
pub trait TGeneral: OnSet + OnResume + OnPowerEvent + OnLoad + OnUnload + Debug + Send {

View file

@ -356,7 +356,7 @@ impl TCpu for Cpu {
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
None
}
}

View file

@ -98,7 +98,7 @@ impl TGpu for Gpu {
fn clock_limits(&mut self, _limits: Option<MinMax<u64>>) {}
fn get_clock_limits(&self) -> Option<&MinMax<u64>> {
fn get_clock_limits(&self) -> Option<MinMax<u64>> {
None
}