Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions crates/cardwire-daemon/src/core/gpu/enumerator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ impl GpuEnumerator {
.as_ref()
.is_some_and(|class| class.starts_with("0x03"))
}) {
info!(
"GPU {} fingerprint: {}",
pci_device.pci_address(),
pci_device.hardware_fingerprint()
);
match self.build_gpu(pci_device) {
Ok(gpu) => {
gpu_list.insert(id, gpu);
Expand Down
2 changes: 2 additions & 0 deletions crates/cardwire-daemon/src/core/gpu/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ mod tests {
Some(1),
Some("0x1002".to_string()),
Some("0x1234".to_string()),
Some("0x1002".to_string()),
Some("0x5678".to_string()),
Some("AMD".to_string()),
Some("RX 7900".to_string()),
Some("amdgpu".to_string()),
Expand Down
74 changes: 74 additions & 0 deletions crates/cardwire-daemon/src/core/pci/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub struct PciDevice {
iommu_group: Option<usize>,
vendor_id: Option<String>,
device_id: Option<String>,
subsystem_vendor_id: Option<String>,
subsystem_device_id: Option<String>,
vendor_name: Option<String>,
device_name: Option<String>,
driver: Option<String>,
Expand All @@ -25,6 +27,12 @@ impl PciDevice {
pub fn device_id(&self) -> &Option<String> {
&self.device_id
}
pub fn subsystem_vendor_id(&self) -> &Option<String> {
&self.subsystem_vendor_id
}
pub fn subsystem_device_id(&self) -> &Option<String> {
&self.subsystem_device_id
}
pub fn vendor_name(&self) -> &Option<String> {
&self.vendor_name
}
Expand All @@ -49,6 +57,8 @@ impl PciDevice {
iommu_group: Option<usize>,
vendor_id: Option<String>,
device_id: Option<String>,
subsystem_vendor_id: Option<String>,
subsystem_device_id: Option<String>,
vendor_name: Option<String>,
device_name: Option<String>,
driver: Option<String>,
Expand All @@ -61,6 +71,8 @@ impl PciDevice {
iommu_group,
vendor_id,
device_id,
subsystem_vendor_id,
subsystem_device_id,
vendor_name,
device_name,
driver,
Expand All @@ -69,6 +81,16 @@ impl PciDevice {
child_pci,
}
}

pub fn hardware_fingerprint(&self) -> String {
format!(
"{}:{}:{}:{}",
self.vendor_id().as_deref().unwrap_or("unknown"),
self.device_id().as_deref().unwrap_or("unknown"),
self.subsystem_vendor_id().as_deref().unwrap_or("unknown"),
self.subsystem_device_id().as_deref().unwrap_or("unknown"),
)
}
}

#[derive(Clone, serde::Serialize, serde::Deserialize, zbus::zvariant::Type)]
Expand Down Expand Up @@ -122,6 +144,8 @@ mod tests {
Some(5),
Some("0x1002".to_string()),
Some("0x7480".to_string()),
Some("0x1002".to_string()),
Some("0x1234".to_string()),
Some("AMD".to_string()),
Some("Navi 31".to_string()),
Some("amdgpu".to_string()),
Expand All @@ -133,6 +157,8 @@ mod tests {
assert_eq!(*pci.iommu_group(), Some(5));
assert_eq!(pci.vendor_id().as_deref(), Some("0x1002"));
assert_eq!(pci.device_id().as_deref(), Some("0x7480"));
assert_eq!(pci.subsystem_vendor_id().as_deref(), Some("0x1002"));
assert_eq!(pci.subsystem_device_id().as_deref(), Some("0x1234"));
assert_eq!(pci.vendor_name().as_deref(), Some("AMD"));
assert_eq!(pci.device_name().as_deref(), Some("Navi 31"));
assert_eq!(pci.driver().as_deref(), Some("amdgpu"));
Expand All @@ -154,16 +180,64 @@ mod tests {
None,
None,
None,
None,
None,
);
assert_eq!(pci.pci_address(), "0000:02:00.0");
assert_eq!(*pci.iommu_group(), None);
assert_eq!(pci.vendor_id().as_deref(), None);
assert_eq!(pci.device_id().as_deref(), None);
assert_eq!(pci.subsystem_vendor_id().as_deref(), None);
assert_eq!(pci.subsystem_device_id().as_deref(), None);
assert_eq!(pci.vendor_name().as_deref(), None);
assert_eq!(pci.device_name().as_deref(), None);
assert_eq!(pci.driver().as_deref(), None);
assert_eq!(pci.class().as_deref(), None);
assert_eq!(pci.parent_pci().as_deref(), None);
assert_eq!(pci.child_pci().as_deref(), None);
}

#[test]
fn test_hardware_fingerprint_is_deterministic() {
let pci = PciDevice::new(
"0000:01:00.0".to_string(),
None,
Some("0x10de".to_string()),
Some("0x2786".to_string()),
Some("0x1458".to_string()),
Some("0x40f5".to_string()),
None,
None,
None,
None,
None,
None,
);

assert_eq!(pci.hardware_fingerprint(), "0x10de:0x2786:0x1458:0x40f5");
assert_eq!(pci.hardware_fingerprint(), pci.hardware_fingerprint());
}

#[test]
fn test_hardware_fingerprint_handles_missing_ids() {
let pci = PciDevice::new(
"0000:02:00.0".to_string(),
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
);

assert_eq!(
pci.hardware_fingerprint(),
"unknown:unknown:unknown:unknown"
);
}
}
26 changes: 26 additions & 0 deletions crates/cardwire-daemon/src/core/pci/pci_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ fn read_pci_devices_using_iommu() -> Result<BTreeMap<String, PciDevice>, Cardwir
for pci_address in group.devices {
let vendor_id = get_vendor_id(&pci_address);
let device_id = get_device_id(&pci_address);
let subsystem_vendor_id = get_subsystem_vendor_id(&pci_address);
let subsystem_device_id = get_subsystem_device_id(&pci_address);

let vendor_key = vendor_id.as_deref().map(normalize_device_id);
let device_key = device_id.as_deref().map(normalize_device_id);
Expand All @@ -55,6 +57,8 @@ fn read_pci_devices_using_iommu() -> Result<BTreeMap<String, PciDevice>, Cardwir
Some(group_id),
vendor_id,
device_id,
subsystem_vendor_id,
subsystem_device_id,
vendor_name,
device_name,
get_driver(&pci_address),
Expand Down Expand Up @@ -87,6 +91,8 @@ fn read_pci_devices_using_sysfs() -> Result<BTreeMap<String, PciDevice>, Cardwir
.ok_or("File name contains invalid UTF-8")?;
let vendor_id = get_vendor_id(name);
let device_id = get_device_id(name);
let subsystem_vendor_id = get_subsystem_vendor_id(name);
let subsystem_device_id = get_subsystem_device_id(name);

let vendor_key = vendor_id.as_deref().map(normalize_device_id);
let device_key = device_id.as_deref().map(normalize_device_id);
Expand All @@ -107,6 +113,8 @@ fn read_pci_devices_using_sysfs() -> Result<BTreeMap<String, PciDevice>, Cardwir
None,
vendor_id,
device_id,
subsystem_vendor_id,
subsystem_device_id,
vendor_name,
device_name,
get_driver(name),
Expand Down Expand Up @@ -136,6 +144,24 @@ fn get_device_id(pci_address: &str) -> Option<String> {
.ok()
}

fn get_subsystem_vendor_id(pci_address: &str) -> Option<String> {
read_sysfs_trim(
Path::new("/sys/bus/pci/devices")
.join(pci_address)
.join("subsystem_vendor"),
)
.ok()
}

fn get_subsystem_device_id(pci_address: &str) -> Option<String> {
read_sysfs_trim(
Path::new("/sys/bus/pci/devices")
.join(pci_address)
.join("subsystem_device"),
)
.ok()
}

fn get_class(pci_address: &str) -> Option<String> {
read_sysfs_trim(
Path::new("/sys/bus/pci/devices")
Expand Down
Loading