Skip to content

Commit f696b64

Browse files
committed
nvidia: Split details into new --nvidia command
PS C:\Users\zoid\framework-system> .\target\debug\framework_tool.exe --nvidia NVIDIA GPU Identification Name: NVIDIA GeForce RTX 5070 Laptop GPU Architecture: Blackwell Board ID: 49664 Firmware VBIOS Version: 98.06.3e.00.0a InfoROM Version: G005.0000.98.01 PCI Bus: C2 Device: 00 Domain: 0000 Device ID: 2D5810DE Subsystem ID: 000EF111 Power Performance State: Eight Current Usage: 7.50 W Default Limit: 100.00 W Min Limit: 5.00 W Max Limit: 100.00 W Total Energy: 26303.86 J Thermal GPU Temperature: 38C Number of Fans: 0 Throttle Reasons None Utilization GPU: 5% Memory: 5% Memory Total: 7.96 GB Used: 0.24 GB Free: 7.38 GB Display Active: Yes Connected: Yes PS C:\Users\zoid\framework-system> .\target\debug\framework_tool.exe --versions Tool Version: 0.4.5 OS Version: 10.0.0.26200 Mainboard Hardware Type: Laptop 16 (AMD Ryzen AI 300 Series) Revision: Unknown UEFI BIOS Version: 03.04 Release Date: 11/06/2025 EC Firmware Build version: tulip-3.0.4-ea09e7a 2025-11-06 10:52:13 lotus@ip-172-26-3-226 Current image: RO PD Controllers PD 0: 0.0.22 (MainFw) PD 1: 0.0.22 (MainFw) PD 2: 0.0.22 (MainFw) Parade Retimers dGPU: 83.0.0.5 Laptop Webcam Module (2nd Gen) Firmware Version: 1.1.1 USB Hub RTL5432 Firmware Version: 0.0.7 Laptop 16 RGB Macropad Firmware Version: 0.3.1 Location: [ ] [ ] [ ] [X] [ ] Laptop 16 Keyboard Module - ANSI Firmware Version: 0.3.1 Location: [X] [ ] [ ] [ ] [ ] Touchpad Firmware Version: v0905 DisplayPort Expansion Card Active Firmware: 101 (3.0.11.065) Inactive Firmware: 008 (3.0.11.008) Operating Mode: MainFw (#2) NVIDIA GPU Name: NVIDIA GeForce RTX 5070 Laptop GPU VBIOS Version: 98.06.3e.00.0a Signed-off-by: Daniel Schaefer <[email protected]>
1 parent c7b5065 commit f696b64

File tree

3 files changed

+192
-39
lines changed

3 files changed

+192
-39
lines changed

framework_lib/src/commandline/clap_std.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ struct ClapCli {
288288
/// File to dump the gpu EEPROM to
289289
#[arg(long)]
290290
dump_gpu_descriptor_file: Option<std::path::PathBuf>,
291+
292+
/// Show NVIDIA GPU information (Framework 16 only)
293+
#[arg(long)]
294+
nvidia: bool,
291295
}
292296

293297
/// Parse a list of commandline arguments and return the struct
@@ -484,6 +488,7 @@ pub fn parse(args: &[String]) -> Cli {
484488
dump_gpu_descriptor_file: args
485489
.dump_gpu_descriptor_file
486490
.map(|x| x.into_os_string().into_string().unwrap()),
491+
nvidia: args.nvidia,
487492
raw_command: vec![],
488493
}
489494
}

framework_lib/src/commandline/mod.rs

Lines changed: 183 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pub struct Cli {
224224
pub flash_gpu_descriptor: Option<(u8, String)>,
225225
pub flash_gpu_descriptor_file: Option<String>,
226226
pub dump_gpu_descriptor_file: Option<String>,
227+
pub nvidia: bool,
227228
// UEFI only
228229
pub allupdate: bool,
229230
pub paginate: bool,
@@ -309,6 +310,7 @@ pub fn parse(args: &[String]) -> Cli {
309310
info: cli.info,
310311
// flash_gpu_descriptor
311312
// flash_gpu_descriptor_file
313+
nvidia: cli.nvidia,
312314
// allupdate
313315
paginate: cli.paginate,
314316
// raw_command
@@ -775,6 +777,7 @@ fn print_versions(ec: &CrosEc) {
775777
print_nvidia_details();
776778
}
777779

780+
/// Brief NVIDIA details for --version output
778781
#[cfg(feature = "nvidia")]
779782
fn print_nvidia_details() {
780783
let nvml = match Nvml::init() {
@@ -784,7 +787,6 @@ fn print_nvidia_details() {
784787
return;
785788
}
786789
};
787-
// Get the first `Device` (GPU) in the system
788790
let device = match nvml.device_by_index(0) {
789791
Ok(device) => device,
790792
Err(err) => {
@@ -795,55 +797,191 @@ fn print_nvidia_details() {
795797

796798
println!("NVIDIA GPU");
797799
println!(
798-
" Name: {}",
800+
" Name: {}",
799801
device.name().unwrap_or("Unknown".to_string())
800802
);
801-
println!(" Architecture: {:?}", device.architecture());
802803
println!(
803-
" VBIOS Version: {}",
804+
" VBIOS Version: {}",
804805
device.vbios_version().unwrap_or("Unknown".to_string())
805806
);
807+
}
808+
809+
/// Detailed NVIDIA information for --nvidia command
810+
#[cfg(feature = "nvidia")]
811+
fn print_nvidia_info() {
812+
let nvml = match Nvml::init() {
813+
Ok(nvml) => nvml,
814+
Err(err) => {
815+
error!("Nvidia, library init fail: {:?}", err);
816+
return;
817+
}
818+
};
819+
let device = match nvml.device_by_index(0) {
820+
Ok(device) => device,
821+
Err(err) => {
822+
error!("Nvidia, device not found: {:?}", err);
823+
return;
824+
}
825+
};
826+
827+
println!("NVIDIA GPU");
828+
829+
// Basic identification
830+
println!("Identification");
806831
println!(
807-
" INFO ROM Ver: {}",
808-
device
809-
.info_rom_image_version()
810-
.unwrap_or("Unknown".to_string())
811-
);
812-
println!(" PCI Info: {:X?}", device.pci_info());
813-
println!(" Performance State: {:?}", device.performance_state());
814-
println!(
815-
" Pwr Mgmt Limit Def: {:?}mW",
816-
device.power_management_limit_default()
817-
);
818-
println!(
819-
" Pwr Mgmt Limit: {:?}mW",
820-
device.power_management_limit()
821-
);
822-
println!(
823-
" Pwr Mgmt Limit Con: {:?}",
824-
device.power_management_limit_constraints()
825-
);
826-
println!(" Pwr Usage: {:?}mW", device.power_usage());
827-
println!(
828-
" Total Energy: {:?}mJ",
829-
device.total_energy_consumption()
832+
" Name: {}",
833+
device.name().unwrap_or("Unknown".to_string())
830834
);
831-
println!(" Serial Number: {:?}", device.serial());
835+
if let Ok(arch) = device.architecture() {
836+
println!(" Architecture: {:?}", arch);
837+
}
838+
if let Ok(serial) = device.serial() {
839+
println!(" Serial Number: {}", serial);
840+
}
841+
if let Ok(part_number) = device.board_part_number() {
842+
println!(" Part Number: {}", part_number);
843+
}
844+
if let Ok(board_id) = device.board_id() {
845+
println!(" Board ID: {}", board_id);
846+
}
847+
848+
// Firmware versions
849+
println!("Firmware");
832850
println!(
833-
" Throttle Reason: {:?}",
834-
device.current_throttle_reasons()
851+
" VBIOS Version: {}",
852+
device.vbios_version().unwrap_or("Unknown".to_string())
835853
);
836854
println!(
837-
" Temperature: {:?}C",
838-
device.temperature(TemperatureSensor::Gpu)
855+
" InfoROM Version: {}",
856+
device
857+
.info_rom_image_version()
858+
.unwrap_or("Unknown".to_string())
839859
);
840-
println!(" Util Rate: {:?}", device.utilization_rates());
841-
println!(" Memory Info: {:?}", device.memory_info());
842-
println!(" Part Number: {:?}", device.board_part_number());
843-
println!(" Board ID: {:?}", device.board_id());
844-
println!(" Num Fans: {:?}", device.num_fans());
845-
println!(" Display Active?: {:?}", device.is_display_active());
846-
println!(" Display Conn?: {:?}", device.is_display_connected());
860+
861+
// PCI information
862+
println!("PCI");
863+
if let Ok(pci) = device.pci_info() {
864+
println!(" Bus: {:02X}", pci.bus);
865+
println!(" Device: {:02X}", pci.device);
866+
println!(" Domain: {:04X}", pci.domain);
867+
println!(" Device ID: {:04X}", pci.pci_device_id);
868+
if let Some(sub_id) = pci.pci_sub_system_id {
869+
println!(" Subsystem ID: {:08X}", sub_id);
870+
}
871+
}
872+
873+
// Power information
874+
println!("Power");
875+
if let Ok(state) = device.performance_state() {
876+
println!(" Performance State: {:?}", state);
877+
}
878+
if let Ok(power) = device.power_usage() {
879+
println!(" Current Usage: {:.2} W", power as f64 / 1000.0);
880+
}
881+
if let Ok(limit) = device.power_management_limit() {
882+
println!(" Power Limit: {:.2} W", limit as f64 / 1000.0);
883+
}
884+
if let Ok(default) = device.power_management_limit_default() {
885+
println!(" Default Limit: {:.2} W", default as f64 / 1000.0);
886+
}
887+
if let Ok(constraints) = device.power_management_limit_constraints() {
888+
println!(
889+
" Min Limit: {:.2} W",
890+
constraints.min_limit as f64 / 1000.0
891+
);
892+
println!(
893+
" Max Limit: {:.2} W",
894+
constraints.max_limit as f64 / 1000.0
895+
);
896+
}
897+
if let Ok(energy) = device.total_energy_consumption() {
898+
println!(" Total Energy: {:.2} J", energy as f64 / 1000.0);
899+
}
900+
901+
// Thermal information
902+
println!("Thermal");
903+
if let Ok(temp) = device.temperature(TemperatureSensor::Gpu) {
904+
println!(" GPU Temperature: {}C", temp);
905+
}
906+
if let Ok(num_fans) = device.num_fans() {
907+
println!(" Number of Fans: {}", num_fans);
908+
}
909+
910+
// Throttling
911+
if let Ok(throttle) = device.current_throttle_reasons() {
912+
println!("Throttle Reasons");
913+
if throttle.is_empty() {
914+
println!(" None");
915+
} else {
916+
if throttle.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::GPU_IDLE) {
917+
println!(" GPU Idle");
918+
}
919+
if throttle.contains(
920+
nvml_wrapper::bitmasks::device::ThrottleReasons::APPLICATIONS_CLOCKS_SETTING,
921+
) {
922+
println!(" Applications Clocks Setting");
923+
}
924+
if throttle.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::SW_POWER_CAP) {
925+
println!(" Software Power Cap");
926+
}
927+
if throttle.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::HW_SLOWDOWN) {
928+
println!(" Hardware Slowdown");
929+
}
930+
if throttle.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::SYNC_BOOST) {
931+
println!(" Sync Boost");
932+
}
933+
if throttle
934+
.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::SW_THERMAL_SLOWDOWN)
935+
{
936+
println!(" Software Thermal Slowdown");
937+
}
938+
if throttle
939+
.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::HW_THERMAL_SLOWDOWN)
940+
{
941+
println!(" Hardware Thermal Slowdown");
942+
}
943+
if throttle
944+
.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::HW_POWER_BRAKE_SLOWDOWN)
945+
{
946+
println!(" Hardware Power Brake Slowdown");
947+
}
948+
if throttle
949+
.contains(nvml_wrapper::bitmasks::device::ThrottleReasons::DISPLAY_CLOCK_SETTING)
950+
{
951+
println!(" Display Clock Setting");
952+
}
953+
}
954+
}
955+
956+
// Utilization
957+
println!("Utilization");
958+
if let Ok(util) = device.utilization_rates() {
959+
println!(" GPU: {}%", util.gpu);
960+
println!(" Memory: {}%", util.memory);
961+
}
962+
963+
// Memory information
964+
println!("Memory");
965+
if let Ok(mem) = device.memory_info() {
966+
let total_gb = mem.total as f64 / (1024.0 * 1024.0 * 1024.0);
967+
let used_gb = mem.used as f64 / (1024.0 * 1024.0 * 1024.0);
968+
let free_gb = mem.free as f64 / (1024.0 * 1024.0 * 1024.0);
969+
println!(" Total: {:.2} GB", total_gb);
970+
println!(" Used: {:.2} GB", used_gb);
971+
println!(" Free: {:.2} GB", free_gb);
972+
}
973+
974+
// Display status
975+
println!("Display");
976+
if let Ok(active) = device.is_display_active() {
977+
println!(" Active: {}", if active { "Yes" } else { "No" });
978+
}
979+
if let Ok(connected) = device.is_display_connected() {
980+
println!(
981+
" Connected: {}",
982+
if connected { "Yes" } else { "No" }
983+
);
984+
}
847985
}
848986

849987
fn print_esrt() {
@@ -1197,6 +1335,11 @@ pub fn run_with_args(args: &Cli, _allupdate: bool) -> i32 {
11971335
println!(" Hdr CRC: {:X}", { header.crc32 });
11981336
}
11991337
}
1338+
} else if args.nvidia {
1339+
#[cfg(feature = "nvidia")]
1340+
print_nvidia_info();
1341+
#[cfg(not(feature = "nvidia"))]
1342+
error!("Not built with nvidia feature");
12001343
} else if let Some(maybe_limit) = args.charge_limit {
12011344
print_err(handle_charge_limit(&ec, maybe_limit));
12021345
} else if let Some((limit, soc)) = args.charge_current_limit {
@@ -1629,6 +1772,7 @@ Options:
16291772
--inputdeck Show status of the input deck
16301773
--inputdeck-mode Set input deck power mode [possible values: auto, off, on] (Framework 16 only)
16311774
--expansion-bay Show status of the expansion bay (Framework 16 only)
1775+
--nvidia Show NVIDIA GPU information (Framework 16 only)
16321776
--charge-limit [<VAL>] Get or set battery charge limit (Percentage number as arg, e.g. '100')
16331777
--charge-current-limit [<VAL>] Get or set battery current charge limit (Percentage number as arg, e.g. '100')
16341778
--get-gpio <GET_GPIO> Get GPIO value by name or all, if no name provided

framework_lib/src/commandline/uefi.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub fn parse(args: &[String]) -> Cli {
9595
dump_gpu_descriptor_file: None,
9696
allupdate: false,
9797
info: false,
98+
nvidia: false,
9899
raw_command: vec![],
99100
};
100101

@@ -250,6 +251,9 @@ pub fn parse(args: &[String]) -> Cli {
250251
} else if arg == "--expansion-bay" {
251252
cli.expansion_bay = true;
252253
found_an_option = true;
254+
} else if arg == "--nvidia" {
255+
cli.nvidia = true;
256+
found_an_option = true;
253257
} else if arg == "--charge-limit" {
254258
cli.charge_limit = if args.len() > i + 1 {
255259
if let Ok(percent) = args[i + 1].parse::<u8>() {

0 commit comments

Comments
 (0)